Tarjan缩点 学习笔记

Tarjan缩点

Tarjan缩点用到的思想就是Tarjan求有向图的强连通分量,然后把强连通分量合在一起,就叫缩点;

模板题:

洛谷 P3387 【模板】缩点

在Tarjan求强连通分量的基础上,加上拓扑排序求DAG的最长路;

代码:

#include<bits/stdc++.h>
#define LL long long
#define pa pair<int,int>
#define ls k<<1
#define rs k<<1|1
#define inf 0x3f3f3f3f
using namespace std;
const int N=200010;
const int M=1000100;
const LL mod=100000000;
int dfn[N],low[N],tot,head[N],cnt,n,m,sta[N],top,ans,w[N],fa[N],L[N],R[N];
int dp[N],in[N];
bool vis[N];
struct Node{
	int to,nex;
}edge[M];
void add(int p,int q){
	edge[cnt].to=q;
	edge[cnt].nex=head[p];
	head[p]=cnt++;
}
void Tarjan(int p){
	dfn[p]=low[p]=++tot;
	if(!vis[p]) vis[p]=true,sta[++top]=p;
	for(int i=head[p];~i;i=edge[i].nex){
		int q=edge[i].to;
		if(!dfn[q]){
			Tarjan(q);
			low[p]=min(low[p],low[q]);
		}
		else if(vis[q]) low[p]=min(low[p],dfn[q]);
	}
	if(dfn[p]==low[p]){
		fa[p]=p;
		vis[p]=false;
		while(sta[top]!=p){
			vis[sta[top]]=false;
			fa[sta[top]]=p;
			w[p]+=w[sta[top]];
			top--;
		}
		top--;
	}
}
int bfs(){
	queue<int>qu;
	for(int i=1;i<=n;i++){
		if(in[i]==0&&fa[i]==i) qu.push(i),dp[i]=w[i];
	}
	while(!qu.empty()){
		int u=qu.front();
		qu.pop();
		for(int i=head[u];~i;i=edge[i].nex){
			int v=edge[i].to;
			dp[v]=max(dp[v],dp[u]+w[v]);
			in[v]--;
			if(in[v]==0) qu.push(v);
		}
	}
	for(int i=1;i<=n;i++) ans=max(ans,dp[i]);
	return ans;
}
int main(){
	memset(head,-1,sizeof(head));
	cin>>n>>m;
	for(int i=1;i<=n;i++) scanf("%d",&w[i]);
	for(int i=1;i<=m;i++){
		scanf("%d%d",&L[i],&R[i]);
		add(L[i],R[i]);
	}
	for(int i=1;i<=n;i++){
		if(!dfn[i]) Tarjan(i);
	}
	cnt=0;//重新建边,相当于缩点 
	memset(head,-1,sizeof(head));
	for(int i=1;i<=m;i++){
		if(fa[L[i]]!=fa[R[i]]){
			in[fa[R[i]]]++;
			add(fa[L[i]],fa[R[i]]);
		}
	}
	cout<<bfs()<<endl;
    return 0;
}
发布了264 篇原创文章 · 获赞 46 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_44291254/article/details/104965759