对于数据的疑问
查看原帖
对于数据的疑问
205782
R浩轩泽Anmicius楼主2021/11/11 20:28

在第四个数据点中,通过搜索发现第1个点能达第470个点,第470个点有一条边直接通向第493个点。而前者的水晶价值9,后者的水晶价值32。

这是不是意味着可以从第470个点买入,第493个点卖出,这样就有23的收入?

但答案是8啊......是数据的问题还是我的问题(好像应该是后者

顺便贴一下我的缩点+拓扑的剧(ju)场(chang)版代码吧。没有注释,看着好玩就行)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<stack> 
#include<queue>
using namespace std;
const int N=6e5;
int n,m,num[2],head[2][N],val[N],visn,stan,dfsn[N],low[N],sta[N],sta_val[2][N],in[N],f[N],g[N],vis_min[N],ans;//f:当前持有 g:当前未持有 
stack<int>s;
queue<int>q;
struct Edge{
	int to;
	int nxt;
}edge[2][N];
inline void add_edge(int x,int y,bool b){
	edge[b][++num[b]].to=y;
	edge[b][num[b]].nxt=head[b][x];
	head[b][x]=num[b];
}
void Tarjan(int u){
	dfsn[u]=low[u]=++visn;
	s.push(u);
	for(int i=head[0][u];i;i=edge[0][i].nxt){
		int v=edge[0][i].to;
		if(!dfsn[v]){
			Tarjan(v);
			low[u]=min(low[u],low[v]);
		}
		else if(!sta[v])//不要省略掉if内容!!! 
		low[u]=min(low[u],dfsn[v]);
	}
	if(dfsn[u]==low[u]){//单独成点或再次返回 
		sta[u]=++stan;
		sta_val[0][stan]=sta_val[1][stan]=val[u];//买入&卖出 
//		if(val[u]==1)
//		cout<<u<<':'<<val[u]<<endl;
		cout<<u<<"->"<<stan<<'	'<<val[u]<<endl;
		while(s.top()!=u){
			sta[s.top()]=stan;
			sta_val[0][stan]=min(sta_val[0][stan],val[s.top()]);
			sta_val[1][stan]=max(sta_val[1][stan],val[s.top()]);
//			if(val[s.top()]==1)
//			cout<<s.top()<<':'<<val[s.top()]<<endl;
//			cout<<s.top()<<':'<<stan<<endl;
			cout<<s.top()<<"->"<<stan<<' '<<val[s.top()]<<endl;
			s.pop();
		}
		s.pop();
	}
}
inline void read(int &x){
	x=0;int f=1;char ch=getchar();
	while(!isdigit(ch)){
		if(ch=='-')f=-1;
		ch=getchar();
	}
	while(isdigit(ch)){
		x=x*10+(ch^48);
		ch=getchar();
	}
	x*=f;
}
int main(){
	freopen("P1073_4.in","r",stdin);
//	freopen("P1073_2.out","w",stdout);
	read(n);read(m);
	memset(f,-0x7f,sizeof f);
	memset(g,-0x7f,sizeof g);
	for(int i=1;i<=n;++i)
	read(val[i]);
	for(int i=1;i<=m;++i){
		int x,y,z;
		read(x);read(y);read(z);
//		if((x==470&&y==493)||(y==470&&x==493&&2))return 0;
		add_edge(x,y,false);
		if(z==2)add_edge(y,x,false);
	}
	Tarjan(1);
	for(int k=1;k<=n;++k)
	for(int i=head[0][k];i;i=edge[0][i].nxt){
		int j=edge[0][i].to;
		if(sta[k]!=sta[j]){
			add_edge(sta[k],sta[j],true);
			++in[sta[j]];
		}
	}//以点为单位遍历边,建立新图 
	q.push(sta[1]);
	f[sta[1]]=-sta_val[0][sta[1]];
	g[sta[1]]=0;
	for(int i=1;i<=stan;++i)
	vis_min[i]=sta_val[0][i];
	while(!q.empty()){
		int u=q.front();q.pop();
		for(int i=head[1][u];i;i=edge[1][i].nxt){
			int v=edge[1][i].to;
//			if(v==sta[470])return 0;
			f[v]=max(f[v],max(f[u],g[u]-sta_val[0][v]));
			g[v]=max(g[v],max(g[u],f[u]+sta_val[1][v]));
			vis_min[v]=min(vis_min[v],vis_min[u]);
			ans=max(ans,sta_val[1][v]-vis_min[v]);
			if(!--in[v])q.push(v);
		}
	}
//	printf("%d\n",max(f[sta[n]]+sta_val[1][sta[n]],g[sta[n]]));//该答案适用于可购买水晶任意次 
	printf("%d\n",ans);
	cout<<val[470]<<' '<<val[493]<<endl;
//	for(int i=1;i<=stan;++i)
//	cout<<i<<":"<<sta_val[0][i]<<' '<<sta_val[1][i]<<' '<<vis_min[i]<<endl;
	return 0;
}
2021/11/11 20:28
加载中...