洛谷P2341 [USACO03FALL / HAOI2006] 受欢迎的牛 G (tarjan缩点)

2022-11-19,,

在本题中很明显,给你一个有向图,要用tarjan缩点。

缩点后,一头牛要受到所有牛的欢迎,那么该点的出度要为0,这是容易证明的:如果该点还有出度,比如a连向b,那么a不受到b的欢迎。所以我们要找出度为0的点,找到后该点中点的个数就是答案。

注意:出度为0的点只能有一个,如果有多个出度为0的点,那么这些点都不受到彼此的欢迎。因此题目有解的情况就是只有一个出度为0的点。

(以上都是缩点后的分析)。

 1 #include<bits/stdc++.h>
2 using namespace std;
3 const int N=10010;
4 int head[N],nxt[N*20],to[N*20],dfn[N],low[N];
5 int du[N],num[N],sum[N],st[N],top;
6 int cnt,tot,idx,n,m;
7 bool vis[N];
8 void add(int u,int v){
9 nxt[++tot]=head[u];
10 head[u]=tot;
11 to[tot]=v;
12 }
13
14 void tarjan(int u){
15 dfn[u]=low[u]=++cnt;
16 st[++top]=u;
17 vis[u]=true;
18 for(int i=head[u];i;i=nxt[i]){
19 int v=to[i];
20 if(!dfn[v]){
21 tarjan(v);
22 low[u]=min(low[u],low[v]);
23 }
24 else if(vis[v]) low[u]=min(low[u],dfn[v]);
25 }
26 if(low[u]==dfn[u]){
27 int vv;
28 ++idx;
29 do{
30 vv=st[top--];
31 vis[vv]=false;
32 num[vv]=idx;
33 sum[idx]++;
34 }while(vv!=u);
35 }
36 }
37
38 int main(){
39 scanf("%d%d",&n,&m);
40 while(m--){
41 int a,b;
42 scanf("%d%d",&a,&b);
43 add(a,b);
44 }
45 for(int i=1;i<=n;i++)
46 if(!dfn[i]) tarjan(i);
47 for(int i=1;i<=n;i++)
48 for(int j=head[i];j;j=nxt[j])
49 if(num[i]!=num[to[j]]) du[num[i]]++;
50 int x=0;
51 for(int i=1;i<=idx;i++)
52 if(!du[i]){
53 if(x) {puts("0");return 0;}
54 x=i;
55 }
56 printf("%d\n",sum[x]);
57 return 0;
58 }

洛谷P2341 [USACO03FALL / HAOI2006] 受欢迎的牛 G (tarjan缩点)的相关教程结束。

《洛谷P2341 [USACO03FALL / HAOI2006] 受欢迎的牛 G (tarjan缩点).doc》

下载本文的Word格式文档,以方便收藏与打印。