题目链接:
http://hihocoder.com/problemset/problem/1185#
题意:
n个点,每个点有一个权值,m条有向边,从1出发,每走到一个点, 就吃掉这个点的草,当没有可以到达的草场或是能够到达的草场都已经被吃光了之后就要返回到1了。求最多可以吃掉多少草。
思路:
提示里面讲的挺好的
如果草场是一个强连通图,那么我们只要走到任意一点,就可以把其他所有的草场都走一遍,并且可以选择任意一个点作为终点。所以把强联通块缩成一个点
因为一个强连通块会被缩成一个点,那么我们可以直接建立一个新的图,这个图中的点对应的是每一个强连通块。若原图中存在边(u,v),连接了属于强连通分量A的点u和属于强连通分量B的点v,那么我们就在新图中建立一条边(A,B)。
先根据原图找到所有的强连通分量,然后再根据原图边的关系建立新的图,之后再用拓扑排序来处理就可以得到最终结果。
缩点之后就没有环了,也就是说我们要求的答案在某条链上面,可以直接dfs下去,找到最大值,也可以用拓扑排序
拓扑排序就是每次取入度为0的点,用它去更新它所能到达的点的最大值,我们不能直接用点的权值更新这个点的答案,因为当有多条边指向一个点的时候,可能会有重复的权值加进来,比如一个点通过两条不同的路径到达另一个点,a->b,b->c, a->d,d->c, 那么a点的权值会在c点加两次,所以我们需要新开一个数组表示答案,本来的权值要保留。
代码:
dfs:
1 #include <bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 #define MS(a) memset(a,0,sizeof(a)) 5 #define MP make_pair 6 #define PB push_back 7 const int INF = 0x3f3f3f3f; 8 const ll INFLL = 0x3f3f3f3f3f3f3f3fLL; 9 inline ll read(){ 10 ll x=0,f=1;char ch=getchar(); 11 while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} 12 while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} 13 return x*f; 14 } 15 // 16 const int maxn = 1e5+10; 17 18 int n,m,tot; 19 vector<int> g[maxn]; 20 int low[maxn],dfn[maxn],vis[maxn],ins[maxn],r[maxn],w[maxn]; 21 stack<int> s; 22 23 void tarjan(int u){ 24 vis[u] = ins[u] = 1; 25 dfn[u] = low[u] = ++tot; 26 s.push(u); 27 for(int i=0; i<(int)g[u].size(); i++){ 28 int v = g[u][i]; 29 if(!vis[v]){ 30 tarjan(v); 31 low[u] = min(low[u],low[v]); 32 }else if(ins[v]){ 33 low[u] = min(low[u],dfn[v]); 34 } 35 } 36 int sum = 0; 37 if(dfn[u] == low[u]){ 38 int t; 39 do{ 40 t = s.top(); 41 s.pop(); 42 ins[t] = 0; 43 sum += w[t]; 44 r[t] = u; 45 }while(u != t); 46 w[u] = sum; 47 } 48 } 49 50 void upd(){ 51 for(int i=1; i<=n; i++){ 52 if(i != r[i]){ 53 for(int j=0; j<(int)g[i].size(); j++){ 54 int v = g[i][j]; 55 if(v != r[i]) g[r[i]].push_back(v); 56 } 57 } 58 } 59 } 60 61 int ans,sum; 62 void dfs(int u){ 63 sum += w[u]; 64 for(int i=0; i<(int)g[u].size(); i++){ 65 int v = g[u][i]; 66 if(u == r[v]) continue; 67 dfs(v); 68 } 69 ans = max(ans,sum); 70 sum -= w[u]; 71 } 72 73 int main(){ 74 cin >> n >> m; 75 for(int i=1; i<=n; i++) 76 scanf("%d",&w[i]); 77 for(int i=0; i<m; i++){ 78 int u,v; scanf("%d%d",&u,&v); 79 g[u].push_back(v); 80 } 81 for(int i=1; i<=n; i++) 82 if(!dfn[i]) tarjan(1); 83 upd(); 84 dfs(1); 85 86 cout << ans << endl; 87 88 return 0; 89 }
拓扑排序:
1 #include <bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 #define MS(a) memset(a,0,sizeof(a)) 5 #define MP make_pair 6 #define PB push_back 7 const int INF = 0x3f3f3f3f; 8 const ll INFLL = 0x3f3f3f3f3f3f3f3fLL; 9 inline ll read(){ 10 ll x=0,f=1;char ch=getchar(); 11 while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} 12 while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} 13 return x*f; 14 } 15 // 16 const int maxn = 1e5+10; 17 18 int n,m,tot; 19 vector<int> g[maxn]; 20 int low[maxn],dfn[maxn],vis[maxn],ins[maxn],r[maxn],w[maxn],pp[maxn],in[maxn]; 21 22 void tarjan(int u){ 23 vis[u] = ins[u] = 1; 24 dfn[u] = low[u] = ++tot; 25 s.push(u); 26 for(int i=0; i<(int)g[u].size(); i++){ 27 int v = g[u][i]; 28 if(!vis[v]){ 29 tarjan(v); 30 low[u] = min(low[u],low[v]); 31 }else if(ins[v]){ 32 low[u] = min(low[u],dfn[v]); 33 } 34 } 35 int sum = 0; 36 if(dfn[u] == low[u]){ 37 int t; 38 do{ 39 t = s.top(); 40 s.pop(); 41 ins[t] = 0; 42 sum += w[t]; 43 r[t] = u; 44 }while(u != t); 45 w[u] = sum; 46 } 47 } 48 49 void upd(){ 50 for(int i=1; i<=n; i++){ 51 if(i != r[i]){ 52 for(int j=0; j<(int)g[i].size(); j++){ 53 int v = g[i][j]; 54 if(v != r[i]) g[r[i]].push_back(v); 55 } 56 } 57 } 58 } 59 void cal(){ 60 for(int i=1; i<=n; i++){ 61 if(i != r[i]) continue; 62 for(int j=0; j<(int)g[i].size(); j++){ 63 int v = g[i][j]; 64 if(r[v] == r[i]) continue; 65 // cout << v << " " << r[v] << endl; 66 in[r[v]]++; 67 } 68 } 69 } 70 71 int ans; 72 73 int main(){ 74 cin >> n >> m; 75 for(int i=1; i<=n; i++) 76 scanf("%d",&w[i]); 77 for(int i=0; i<m; i++){ 78 int u,v; scanf("%d%d",&u,&v); 79 g[u].push_back(v); 80 } 81 for(int i=1; i<=n; i++) 82 if(!dfn[i]) tarjan(1); 83 upd(); cal(); 84 // for(int i=1; i<=n; i++) 85 // cout << in[i] << endl; 86 queue<int> q; 87 q.push(r[1]); 88 pp[1] = w[r[1]]; 89 while(!q.empty()){ 90 int u = q.front(); q.pop(); 91 if(u != r[u]) continue; 92 ans = max(ans,pp[u]); 93 for(int i=0; i<(int)g[u].size(); i++){ 94 int v = g[u][i]; 95 if(u == r[v]) continue; 96 in[v]--; 97 pp[v] = max(pp[v],w[v]+pp[u]); 98 if(in[v] == 0) q.push(v); 99 } 100 } 101 102 cout << ans << endl; 103 104 return 0; 105 }