洛谷 P3387 【模板】缩点 【Tarjan SCC】

 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 }

猜你喜欢

转载自www.cnblogs.com/ZhenghangHu/p/9265397.html
今日推荐