1 #include<iostream> 2 #include<vector> 3 #include<stack> 4 #include<queue> 5 #include<map> 6 using namespace std; 7 8 int a[10005],prev[10005],low[10005],instack[10005];//score[i]是新的点权 9 10 vector<int> edge[10005],bian[10005]; 11 stack<int> s; 12 queue<int> q;//先进先出 13 map<int,int> scc;// m[i]代表i所在的联通分量 14 15 int indegree[10005],m1[100005],m2[100005],score[10005],ans,time; 16 17 void tarjan(int u){ 18 prev[u] = low[u] = ++time;//low[u]代表以u为根的子树中(包括u)所能达到的prev最小的值 19 s.push(u); instack[u]=1;//每个点都是SCC的一部分 20 for(int i=0;i<edge[u].size();i++){ 21 int v = edge[u][i]; 22 if( prev[v]==0 ) { 23 tarjan(v); 24 low[u] = min( low[u],low[v] ); 25 } 26 else if( instack[v] ){//指向祖先,如果不是祖先那一定出栈了 27 low[u] = min( low[u],prev[v] );//u可能指向多个祖先 【low的定义就是当前节点所能达到的最浅的层数,所以要用min不停迭代】 28 } 29 } 30 if( prev[u]==low[u] ){ 31 while( s.top()!=u ) { 32 int node = s.top(); instack[node]=0; s.pop(); score[u]+=a[node]; scc[node]=u; 33 } 34 instack[u]=0; s.pop(); score[u]+=a[u]; scc[u]=u; 35 } 36 37 } 38 39 int dfs(int u){ 40 if(bian[u].size()==0) return score[u]; 41 int count=0; 42 for(int i=0;i<bian[u].size();i++){ 43 int v= bian[u][i]; 44 count = max(count,score[u]+dfs(v)); 45 } 46 return count; 47 } 48 49 int main(){ 50 int n,m; cin>>n>>m; 51 for(int i=1;i<=n;i++) cin>>a[i]; 52 for(int i=1;i<=m;i++){ 53 int u,v; cin>>u>>v; 54 edge[u].push_back(v); 55 m1[i]=u; m2[i]=v; 56 } 57 58 for(int i=1;i<=n;i++){ 59 if( prev[i]==0 ) tarjan(i);//以i为根的搜索树缩点 60 } 61 62 //重新建图 63 //扫一遍原图中的所有边,如果该边对应的两个点在同一个scc中,不用建边;否则,在两个scc间建一条有向边。转化为DAG 64 for(int i=1;i<=m;i++){ 65 if( scc[ m1[i] ] == scc[ m2[i] ] ) continue; 66 else { 67 bian[ scc[m1[i]] ].push_back( scc[m2[i]] ); 68 indegree[ scc[m2[i]] ]++; 69 } 70 } 71 72 //搜索所有入度为0的顶点 73 for(int i=1;i<=n;i++){ 74 if(indegree[i]==0) ans=max( ans,dfs(i) ); 75 } 76 77 cout<<ans; 78 79 return 0; 80 }
洛谷 P3387 【模板】缩点 【Tarjan SCC】
猜你喜欢
转载自www.cnblogs.com/ZhenghangHu/p/9265397.html
今日推荐
周排行