1. 程式人生 > >洛谷 P3387 【模板】縮點 【Tarjan SCC】

洛谷 P3387 【模板】縮點 【Tarjan SCC】

str 新的 ace map sco pop 建圖 出棧 多個

 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】