hihoCoder #1185 : 连通性·三(强联通分量+拓扑排序)

Posted Yeader

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了hihoCoder #1185 : 连通性·三(强联通分量+拓扑排序)相关的知识,希望对你有一定的参考价值。

#1185 : 连通性·三

时间限制:10000ms
单点时限:1000ms
内存限制:256MB

描述

暑假到了!!小Hi和小Ho为了体验生活,来到了住在大草原的约翰家。今天一大早,约翰因为有事要出去,就拜托小Hi和小Ho忙帮放牧。

约翰家一共有N个草场,每个草场有容量为W[i]的牧草,N个草场之间有M条单向的路径。

小Hi和小Ho需要将牛羊群赶到草场上,当他们吃完一个草场牧草后,继续前往其他草场。当没有可以到达的草场或是能够到达的草场都已经被吃光了之后,小hi和小Ho就把牛羊群赶回家。

一开始小Hi和小Ho在1号草场,在回家之前,牛羊群最多能吃掉多少牧草?

举个例子:

技术分享图片

图中每个点表示一个草场,上部分数字表示编号,下部分表示草场的牧草数量w。

在1吃完草之后,小Hi和小Ho可以选择把牛羊群赶到2或者3,假设小Hi和小Ho把牛羊群赶到2:

吃完草场2之后,只能到草场4,当4吃完后没有可以到达的草场,所以小Hi和小Ho就把牛羊群赶回家。

若选择从1到3,则可以到达5,6:

选择5的话,吃完之后只能直接回家。若选择6,还可以再通过6回到3,再到5。

所以该图可以选择的路线有3条:

1->2->4 		total: 11
1->3->5 		total: 9
1->3->6->3->5: 		total: 13
  

所以最多能够吃到的牧草数量为13。

 

 

本题改编自USACO月赛金组

提示:强连通分量

输入

第1行:2个正整数,N,M。表示点的数量N,边的数量M。1≤N≤20,000, 1≤M≤100,000

第2行:N个正整数,第i个整数表示第i个牧场的草量w[i]。1≤w[i]≤100,000

第3..M+2行:2个正整数,u,v。表示存在一条从u到v的单向路径。1≤u,v≤N

输出

第1行:1个整数,最多能够吃到的牧草数量。

代码

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<vector>
 5 #include<stack>
 6 #include<queue>
 7 #include<algorithm>
 8 using namespace std;
 9 const int N=2e4+5;
10 
11 vector<int>v[N];
12 vector<int>gra[N];
13 stack<int>sk;
14 int n,m,cnt,num,ans;
15 int val[N],low[N],dfn[N],fa[N],sum[N],indeg[N],dp[N];
16 bool vis[N];
17 
18 //求出强连通分量
19 void tarjan(int u){
20     low[u]=dfn[u]=++cnt;
21     sk.push(u);
22     for(int i=0;i<v[u].size();i++){
23         int t=v[u][i];
24         if(!dfn[t]){
25             tarjan(t);
26             low[u]=min(low[u],low[t]);
27         }
28         else if(!fa[t]) low[u]=min(low[u],dfn[t]);
29     }
30     if(low[u]==dfn[u]){
31         num++;
32         while(!sk.empty()){
33             int t=sk.top();
34             sk.pop();
35             fa[t]=num;
36             sum[num]+=val[t];
37             if(t==u) break;
38         }
39     }
40 }
41 
42 //拓扑排序求最大价值
43 int topo(){
44     queue<int>q;
45     for(int i=1;i<=num;i++){
46         if(indeg[i]==0)
47             q.push(i);
48     }
49     int ans=0;
50     while(!q.empty()){
51         int k=q.front();
52         q.pop();
53         dp[k]+=sum[k];
54         ans=max(dp[k],ans);
55         for(int i=0;i<gra[k].size();i++){
56             int t=gra[k][i];
57             indeg[t]--;
58             dp[t]=max(dp[t],dp[k]);
59             if(indeg[t]==0)
60                 q.push(t);
61         }
62     }
63     return ans;
64 }
65 
66 int main(){
67     scanf("%d%d",&n,&m);
68     for(int i=1;i<=n;i++) scanf("%d",&val[i]);
69     for(int i=1;i<=m;i++){
70         int a,b;
71         scanf("%d%d",&a,&b);
72         v[a].push_back(b);
73     }
74     tarjan(1);                  //起点是1
75     //建新图
76     for(int i=1;i<=n;i++){
77         if(fa[i]==0) continue;
78         for(int j=0;j<v[i].size();j++){
79             int t=v[i][j];
80             if(fa[i]!=fa[t])
81                 gra[fa[i]].push_back(fa[t]);
82         }
83     }
84     //计算入度
85     for(int i=1;i<=num;i++){
86         for(int j=0;j<gra[i].size();j++){
87             int t=gra[i][j];
88             indeg[t]++;
89         }
90     }
91     //利用拓扑排序算出答案
92     printf("%d\n",topo());
93     return 0;
94 }

 

以上是关于hihoCoder #1185 : 连通性·三(强联通分量+拓扑排序)的主要内容,如果未能解决你的问题,请参考以下文章

hihoCoder #1185 : 连通性·三(强联通分量+拓扑排序)

hihoCoder 1185 连通性·三(Tarjan缩点+暴力DFS)

HihoCoder 1185 : 连通性·三(强连通缩点)

hihoCoder#1185 : 连通性·三 tarjan求强联通分量 缩点 dfs/拓扑排序求路径和最大值

[HihoCoder-1185] 连通性·三 tarjan+缩点

强连通分量问题