60分求助,我实在看不出为什么会wa呜呜呜
查看原帖
60分求助,我实在看不出为什么会wa呜呜呜
492894
北海几吹夏楼主2021/9/10 19:42

球球您帮帮萌新吧呜呜呜

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<queue>

using namespace std;
const int MAX=1e5+10,N=1e4+10;
int head[N],cnt,dfn[N],vis[N],low[N];
int n,m,cnt2,cnt3,stac[N],cnt4;
int ind[N],val[N],h[N],va[N];
int fin[N];
struct edge{
	int u,v,next;
}ed[MAX],ad[MAX];

queue <int> q;

void add(int u,int v){
	ed[++cnt].v=v;
	ed[cnt].u=u;
	ed[cnt].next=head[u];
	head[u]=cnt;
}

void tarjan(int u){
	dfn[u]=low[u]=++cnt2;
	stac[++cnt3]=u;
	vis[u]=1;

	for(int i=head[u];i;i=ed[i].next){
		int v=ed[i].v;
		if(!dfn[v]){
			tarjan(v);
			low[u]=min(low[u],low[v]);
			
		}else if(vis[v]){
			low[u]=min(low[u],low[v]);//相同的根节点 表示缩成一个点
		}
	}
	if(low[u]==dfn[u]){
		int y;
		while(y=stac[cnt3--]){
			vis[stac[cnt3+1]]=0;
			va[low[u]]+=val[y];
			if(u==y){
				break;
			}
	
		}
		
	}
	
}

int topo(){
	for(int i=1;i<=n;i++){
		if(!ind[i]&&low[i]==dfn[i]){
			q.push(low[i]);
			fin[low[i]]=va[low[i]];
		}
	}
	while(!q.empty()){
		int u=q.front();
		q.pop();
		for(int i=h[u];i;i=ad[i].next){
			int v=ad[i].v;
			ind[v]--;
			fin[v]=max(fin[v],fin[u]+va[v]);
			if(!ind[v]){
				q.push(v);
			}
		}
	}
	int maxx=0;
	for(int i=1;i<=n;i++){
		maxx=max(maxx,fin[i]);
	}

	return maxx;
}

int main(){
	cin>>n>>m;
	int a,b;
	for(int i=1;i<=n;i++){
		cin>>val[i];
	}
	for(int i=1;i<=m;i++){
		cin>>a>>b;
		add(a,b);
	}
	
	for(int i=1;i<=n;i++){
		if(!dfn[i]){
			tarjan(i);
		}
	}

	for(int i=1;i<=cnt;i++){
		int u=ed[i].u,v=ed[i].v;
		if(low[u]!=low[v]){
			ad[++cnt4].u=low[u];
			ad[cnt4].v=low[v];
			ad[cnt4].next=h[low[u]];
			h[low[u]]=cnt4;
		}
	}

	cout<<topo()<<endl;

	
	return 0;
}

下面是另一个ac的版本。。。我感觉是一样的,为什么上面的不对呢?

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<cstring>
using namespace std;
const int MAX=1e5+10,N=1e4+10;
int head[N],cnt,bj[N],dfn[N],vis[N],low[N];
int n,m,cnt2,cnt3,stac[N],cnt4,total;
int ind[N],val[N],h[N],va[N];
int fin[N];
struct edge{
	int u,v,next;
}ed[MAX],ad[MAX];

queue <int> q;

void add(int u,int v){
	ed[++cnt].v=v;
	ed[cnt].u=u;
	ed[cnt].next=head[u];
	head[u]=cnt;
}

void tarjan(int u){
	dfn[u]=low[u]=++cnt2;						//dfn是时间戳,low表示强连通分量的最小点(第一个到的dfn的值) 
	stac[++cnt3]=u;								//把这个数入栈 
	vis[u]=1;									//表示u已入栈 
	for(int i=head[u];i!=-1;i=ed[i].next){
		int v=ed[i].v;
		if(!dfn[v]){							//如果v没有跑过(如果没跑过的话dfn是0) 
			tarjan(v);							//继续向下跑 
			low[u]=min(low[u],low[v]);			//跑完之后比较当前的low和v的low哪个更小, 
			
		}else if(vis[v]){						//如果跑过了  并且在栈里 
			low[u]=min(low[u],low[v]);			//说明是强连通分量,比较哪个的low更小 
		}
	}
	if(low[u]==dfn[u]){							//如果dfn和low相等,说明此时的u就是根节点 
		int y;
		while(y=stac[cnt3--]){					//出栈 
			vis[stac[cnt3+1]]=0;				//不要忘了标记vis=0,表示不在栈里 
			va[u]+=val[y];
			bj[y]=u;							//bj[y]是y的祖先节点 
			if(u==y){							//如果出栈到自己,结束 
				break;
			}
			
		}
		
	}
	
}

int topo(){							//拓扑排序 
	for(int i=1;i<=n;i++){
		if(!ind[i]&&bj[i]==i){
			q.push(bj[i]);
			fin[bj[i]]=va[bj[i]];	//fin i的意思是到达缩完点i的最大值 
		}
	}
	while(!q.empty()){
		int u=q.front();
		q.pop();
		for(int i=h[u];i!=-1;i=ad[i].next){
			int v=ad[i].v;
			ind[v]--;
			fin[v]=max(fin[v],fin[u]+va[v]);		//小dp,比较fin u过来 和它本身的fin 哪个大(呜呜没解释清楚) 
			if(!ind[v]){
				q.push(v);							
			}
		}
	}
	int maxx=0;
	for(int i=1;i<=n;i++){							//循环一遍,找最大的fin 
		maxx=max(maxx,fin[i]);
	}
	return maxx;
}

int main(){
	cin>>n>>m;
	memset(head,-1,sizeof(head));
	memset(h,-1,sizeof(h));
	int a,b;
	for(int i=1;i<=n;i++){
		cin>>val[i];
	}
	for(int i=1;i<=m;i++){
		cin>>a>>b;
		add(a,b);
	}
	
	for(int i=1;i<=n;i++){				//每个点开始都tarjan一遍 
		if(!dfn[i]){					//没有跑过i的话 
			tarjan(i);						//因为可能不止一个图。。。 
		}
	 }

	for(int i=1;i<=cnt;i++){			//两遍链式前向星 
		int u=ed[i].u,v=ed[i].v;
		if(bj[u]!=bj[v]){				//如果祖先节点不同 
			ad[++cnt4].u=bj[u];
			ad[cnt4].v=bj[v];
			ad[cnt4].next=h[bj[u]];
			h[bj[u]]=cnt4;
			ind[bj[v]]++;				//入度++ 
		}
	}
	cout<<topo()<<endl;

	
	return 0;
}
2021/9/10 19:42
加载中...