求最小点基 poj 1236
题意:
在一个信息网络当中,为了能够告知学校最新信息,现在告诉你各个学校之间的联系关系,问你最少能够通知多少个学校就能完成对所有的学校通知完毕,因为具有内在联系的学校会相互通知,若我们现在想要通知其中一个学校就能通过它们内部传递然后就能使所有学校都知道,那么此时我们使某些学校存在一个联系就可以了,问这样的联系我们最少需要创建多少。
解题思路:只要算出强连通的个数,并且知道哪些强连通没有入度,计数,然后第二个答案只要计数所有强连通入度为0,出度为0的个数,然后取两者最大值,这就是要添加的最少边数。。
View Code
1 #include<iostream> 2 #include<stdio.h> 3 #define min(a,b) a<b?a:b 4 #define max(a,b) a>b?a:b 5 #define S 110 6 using namespace std; 7 int n; 8 int map[S][S],stack[S],dfn[S],low[S],top,Time,exist[S],weight[S],Count,ind[S],outd[S]; 9 void tarjan(int u) 10 { 11 dfn[u]=low[u]=++Time; 12 stack[top++]=u; 13 exist[u]=1; 14 for(int to=1;to<=n;to++) 15 { 16 if(!dfn[to]&&map[u][to]==1) 17 { 18 tarjan(to); 19 low[u]=min(low[u],low[to]); 20 } 21 else 22 { 23 if(map[u][to]==1&&exist[to]==1) 24 low[u]=min(low[u],dfn[to]); 25 } 26 } 27 if(low[u]==dfn[u]) 28 { 29 Count++; 30 int v; 31 do 32 { 33 v=stack[top-1]; 34 exist[v]=0; 35 weight[v]=Count; 36 top--; 37 }while(u!=v); 38 } 39 } 40 int main() 41 { 42 int end; 43 while(scanf("%d",&n)!=EOF) 44 { 45 for(int i=1;i<=n;i++) 46 { 47 for(int j=1;j<=n;j++) 48 { 49 if(i==j)map[i][j]=1; 50 else 51 map[i][j]=-1; 52 } 53 ind[i]=outd[i]=exist[i]=dfn[i]=low[i]=0; 54 } 55 for(int i=1;i<=n;i++) 56 { 57 scanf("%d",&end); 58 while(end) 59 { 60 map[i][end]=1; 61 scanf("%d",&end); 62 } 63 } 64 Count=Time=top=0; 65 for(int i=1;i<=n;i++) 66 { 67 if(!dfn[i]) 68 tarjan(i); 69 } 70 for(int i=1;i<=n;i++) 71 { 72 for(int j=1;j<=n;j++) 73 { 74 if(map[i][j]==1&&weight[i]!=weight[j]) 75 { 76 ind[weight[j]]++; 77 outd[weight[i]]++; 78 } 79 } 80 } 81 int max1=0,max2=0; 82 for(int i=1;i<=Count;i++) 83 { 84 if(ind[i]==0)max1++; 85 if(outd[i]==0)max2++; 86 } 87 max2=max(max1,max2); 88 printf("%d\n",max1); 89 if(Count==1)printf("0\n"); 90 else 91 printf("%d\n",max2); 92 } 93 return 0; 94 }