白书上的例题
做一遍tarjan后,缩点,每一个scc节点的权为它的结点数,做一次DAG上的动规,求出路径上的最大点权和,就可以了
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 #include<stack> 6 #include<vector> 7 using namespace std; 8 9 const int maxn = 5005; 10 int n,m; 11 int first[maxn]; 12 int sc[maxn],scn[maxn],low[maxn],pre[maxn]; 13 int scnt,ecnt,dfs_clock; 14 int dp[maxn]; 15 16 int first1[maxn]; 17 int ecnt1; 18 19 struct Edge{ 20 int v,next; 21 }e[maxn*10]; 22 23 Edge e1[maxn*10]; 24 25 stack<int> S; 26 27 void init(){ 28 ecnt = ecnt1 = 0; 29 memset(first,-1,sizeof(first)); 30 memset(first1,-1,sizeof(first1)); 31 memset(dp,0,sizeof(dp)); 32 } 33 34 void addedges(int u,int v){ 35 e[ecnt].v = v; 36 e[ecnt].next = first[u]; 37 first[u] = ecnt++; 38 } 39 40 void addedges1(int u,int v){ 41 e1[ecnt1].v = v; 42 e1[ecnt1].next = first1[u]; 43 first1[u] = ecnt1++; 44 } 45 46 void dfs(int u){ 47 low[u] = pre[u] = ++dfs_clock; 48 S.push(u); 49 for(int i = first[u];~i;i = e[i].next){ 50 int v = e[i].v; 51 if(!pre[v]){ 52 dfs(v); 53 low[u] = min(low[u],low[v]); 54 } 55 else if(!sc[v]) low[u] = min(low[u],pre[v]); 56 } 57 if(pre[u] == low[u]){ 58 scnt++; 59 for(;;){ 60 int x = S.top();S.pop(); 61 sc[x] = scnt; 62 scn[scnt]++; 63 if(x == u) break; 64 } 65 } 66 } 67 68 void find_scc(){ 69 while(!S.empty()) S.pop(); 70 scnt = dfs_clock = 0; 71 memset(low,0,sizeof(low));memset(pre,0,sizeof(pre)); 72 memset(sc,0,sizeof(sc));memset(scn,0,sizeof(scn)); 73 74 for(int i = 1;i <= n;i++) if(!pre[i]) dfs(i); 75 } 76 77 int solve(int p){ 78 if(dp[p]) return dp[p]; 79 for(int i = first1[p];~i;i = e1[i].next){ 80 int v = e1[i].v; 81 dp[p] = max(dp[p],solve(v)); 82 } 83 return dp[p] = dp[p] + scn[p]; 84 } 85 86 87 int main(){ 88 int T; 89 scanf("%d",&T); 90 while(T--){ 91 init(); 92 scanf("%d %d",&n,&m); 93 for(int i = 0;i < m;i++ ){ 94 int u,v; 95 scanf("%d %d",&u,&v); 96 addedges(u,v); 97 } 98 find_scc(); 99 100 for(int u = 1;u <= n;u++){ 101 for(int i = first[u];~i;i = e[i].next){ 102 int v = e[i].v; 103 if(sc[u] != sc[v]) addedges1(sc[u],sc[v]); 104 } 105 } 106 107 108 int ans = 0; 109 for(int i = 1;i <= scnt;i++) ans = max(ans,solve(i)); 110 printf("%d ",ans); 111 } 112 return 0; 113 }
还有另一种做法是,建立一个超级源点,与入度为0的scc节点连接,做一次spfa,求出路径上的最大点权和
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 #include<stack> 6 #include<vector> 7 #include<queue> 8 using namespace std; 9 10 const int maxn = 5005; 11 const int INF = 1000000005; 12 int n,m; 13 int first[maxn]; 14 int sc[maxn],scn[maxn],low[maxn],pre[maxn]; 15 int scnt,ecnt,dfs_clock; 16 int dp[maxn]; 17 18 int du[maxn]; 19 int dis[maxn]; 20 int inq[maxn]; 21 22 int first1[maxn]; 23 int ecnt1; 24 25 struct Edge{ 26 int v,next; 27 }e[maxn*10]; 28 29 Edge e1[maxn*10]; 30 31 stack<int> S; 32 vector<int> g[maxn]; 33 int val[maxn]; 34 35 void init(){ 36 ecnt = ecnt1 = 0; 37 memset(first,-1,sizeof(first)); 38 memset(val,0,sizeof(val)); 39 memset(du,0,sizeof(du)); 40 } 41 42 void addedges(int u,int v){ 43 e[ecnt].v = v; 44 e[ecnt].next = first[u]; 45 first[u] = ecnt++; 46 } 47 48 void dfs(int u){ 49 low[u] = pre[u] = ++dfs_clock; 50 S.push(u); 51 for(int i = first[u];~i;i = e[i].next){ 52 int v = e[i].v; 53 if(!pre[v]){ 54 dfs(v); 55 low[u] = min(low[u],low[v]); 56 } 57 else if(!sc[v]) low[u] = min(low[u],pre[v]); 58 } 59 if(pre[u] == low[u]){ 60 scnt++; 61 for(;;){ 62 int x = S.top();S.pop(); 63 sc[x] = scnt; 64 val[scnt]++; 65 if(x == u) break; 66 } 67 } 68 } 69 70 void find_scc(){ 71 while(!S.empty()) S.pop(); 72 scnt = dfs_clock = 0; 73 memset(low,0,sizeof(low));memset(pre,0,sizeof(pre)); 74 memset(sc,0,sizeof(sc));memset(scn,0,sizeof(scn)); 75 76 for(int i = 1;i <= n;i++) if(!pre[i]) dfs(i); 77 } 78 79 80 int spfa(){ 81 memset(inq, 0, sizeof(inq)); 82 queue<int>q; 83 g[0].clear(); 84 q.push(0); 85 dis[0] = 0; val[0] = 0; 86 for(int i = 1; i <= scnt; i++){if(du[i] == 0)g[0].push_back(i); dis[i] = -INF;} 87 int ans = 0; 88 while(!q.empty()){ 89 int u = q.front(); q.pop(); inq[u] = 0; 90 for(int i = 0; i < g[u].size(); i++){ 91 int v = g[u][i]; 92 if(dis[v] < dis[u] + val[v]){ 93 dis[v] = dis[u] + val[v]; 94 ans = max(ans, dis[v]); 95 if(inq[v] == 0)inq[v] = 1, q.push(v); 96 } 97 } 98 } 99 return ans; 100 } 101 102 int main(){ 103 int T; 104 scanf("%d",&T); 105 while(T--){ 106 init(); 107 scanf("%d %d",&n,&m); 108 for(int i = 0;i < m;i++ ){ 109 int u,v; 110 scanf("%d %d",&u,&v); 111 addedges(u,v); 112 } 113 find_scc(); 114 for(int i = 1;i <= scnt;i++) g[i].clear(); 115 116 for(int u = 1;u <= n;u++){ 117 for(int i = first[u];~i;i = e[i].next){ 118 int v = e[i].v; 119 if(sc[u] != sc[v]) g[sc[u]].push_back(sc[v]),du[sc[v]]++; 120 } 121 } 122 printf("%d ",spfa()); 123 } 124 return 0; 125 }