1. 程式人生 > >haoi2006_受歡迎的牛_Solution

haoi2006_受歡迎的牛_Solution

efi 縮點 true -c count num sizeof min tail

Brief Solution:

強連通tarjan+壓縮點+判斷是否除了一個點,其它點都有出度

Detailed Solution:

把牛看成點
若一個點b能到達點a,則b認為a受歡迎
若所有的點都能到達點a,則a被所有的牛歡迎

對於某個強連通中的點,任意兩點可互達,互相受歡迎
對圖求強連通,並把強連通壓縮成一個點
若點a向與點a不在同一個強連通集合的點b,則點a所在的集合指向點b所在的集合(邊)

若一個強連通集合的點(新圖的點A)能被所有的點到達,則新圖所有的點能到達點A
此時新圖沒有環,若一個點A能被所有的點到達,則除了該點,其它點的出度都不為0(圖必有沒有出度的點,因為圖沒有環)
則能被所有的點到達的點只有一個,否則會有環,矛盾
(在沒有環的條件下,圖中所有的點到匯集(到達)該點)

Code:

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <stdbool.h>
  4 #include <malloc.h>
  5 #define maxn 10000
  6 #define maxm 50000
  7 
  8 struct node
  9 {
 10     long d;
 11     struct node *next;
 12 }*info[maxn+1];
 13 long x[maxm+1],y[maxm+1];
 14 long dfn[maxn+1
],low[maxn+1],stack[maxn+1],num[maxn+1],ans[maxn+1],count=0,sum=0; 15 bool vis[maxn+1],vis_stack[maxn+1],next[maxn+1]; 16 17 long min(long a,long b) 18 { 19 if (a>b) 20 return b; 21 else 22 return a; 23 } 24 25 void tarjan(long d) 26 { 27 vis[d]=false; 28 count++;
29 stack[count]=d; 30 dfn[d]=count; 31 low[d]=count; 32 struct node *p; 33 long nd,pre; 34 p=info[d]; 35 while (p) 36 { 37 nd=p->d; 38 if (vis[nd]==true) 39 { 40 tarjan(nd); 41 low[d]=min(low[d],low[nd]); 42 } 43 else if (vis_stack[nd]==true) 44 low[d]=min(low[d],dfn[nd]); 45 p=p->next; 46 } 47 pre=count; 48 if (dfn[d]==low[d]) 49 { 50 sum++; 51 while (d!=stack[count]) 52 { 53 num[stack[count]]=sum; 54 vis_stack[stack[count]]=false; 55 count--; 56 } 57 num[stack[count]]=sum; 58 vis_stack[stack[count]]=false; 59 count--; 60 ans[sum]=pre-count; //count+1~pre 61 } 62 } 63 64 int main() 65 { 66 long i,n,m,d; 67 struct node *p; 68 scanf("%ld%ld",&n,&m); 69 // for (i=1;i<=n;i++) 70 // info[i]=NULL; 71 for (i=1;i<=m;i++) 72 { 73 scanf("%ld%ld",&x[i],&y[i]); 74 p=(struct node *) malloc (sizeof(struct node)); 75 p->d=y[i]; 76 p->next=info[x[i]]; 77 info[x[i]]=p; 78 } 79 for (i=1;i<=n;i++) 80 { 81 vis[i]=true; 82 vis_stack[i]=true; 83 } 84 for (i=1;i<=n;i++) 85 if (vis[i]==true) 86 tarjan(i); 87 for (i=1;i<=sum;i++) 88 next[i]=false; 89 for (i=1;i<=m;i++) 90 if (num[x[i]]!=num[y[i]]) 91 next[num[x[i]]]=true; 92 d=0; 93 for (i=1;i<=sum;i++) 94 if (next[i]==false) 95 { 96 if (d==0) 97 d=i; 98 else 99 { 100 d=-1; 101 break; 102 } 103 } 104 if (d==-1) 105 printf("0\n"); 106 else 107 printf("%ld\n",ans[d]); 108 return 0; 109 }

haoi2006_受歡迎的牛_Solution