(转载) poj1236 - Network of Schools

 

看到一篇挺好的代码,适合初学者,转载自 博主 wangjian8006

原地址:http://blog.csdn.net/wangjian8006/article/details/7888558

题目大意:有N个学校,从每个学校都能从一个单向网络到另外一个学校,两个问题
1:初始至少需要向多少个学校发放软件,使得网络内所有的学校最终都能得到软件。
2:至少需要添加几条边,使任意向一个学校发放软件后,经过若干次传送,网络内所有的学校最终都能得到软件。
解题思路:
首先找连通分量,然后看连通分量的入度为0点的总数,出度为0点的总数,那么问要向多少学校发放软件,就是入度为零的个数,这样才能保证所有点能够找到
然后第二问添加多少条边可以得到使整个图达到一个强连通分量,答案是入度为0的个数和出度为0的个数中最大的那个
为什么会这样呢,经过我同学的讨论,将这个图的所有子树找出来,然后将一棵子树的叶子结点(出度为0)连到另外一棵子树的根结点上(入度为0),这样将所有的叶子结点和根节点全部消掉之后,就可以得到一整个强连通分量,看最少多少条边,这样就是看叶子结点和根节点哪个多,即出度为0和入度为0哪个多。我只能说这种策略是正确的,适用于一般图,但其实我觉得也不能够很有力的证明这个结论成立

 1 /* 
 2 kosaraju 
 3 Memory 224K 
 4 Time    0MS 
 5 */  
 6 #include <iostream>  
 7 using namespace std;  
 8 #define MAXV 110  
 9 #define max(a,b) (a>b?a:b)  
10   
11 int map[MAXV][MAXV],order[MAXV],belong[MAXV],indegree[MAXV],outdegree[MAXV];  
12 int n,num,count;  
13 bool vis[MAXV];  
14   
15 void dfs(int x){  
16     int i;  
17     vis[x]=1;  
18     for(i=1;i<=n;i++)  
19         if(map[x][i] && !vis[i])  
20             dfs(i);  
21     order[++num]=x;  
22 }  
23   
24 void dfst(int x){  
25     int i;  
26     belong[x]=count;        //记录结点属于哪个连通分量  
27     vis[x]=1;  
28     for(i=1;i<=n;i++)  
29         if(!vis[i] && map[i][x])  
30             dfst(i);  
31 }  
32   
33 void kosaraju(){  
34     int i;  
35     memset(vis,0,sizeof(vis));  
36     num=count=0;  
37     for(i=1;i<=n;i++)        //第一次搜索将时间戳从小到大排序  
38         if(!vis[i]) dfs(i);  
39     memset(vis,0,sizeof(vis));  
40   
41     for(i=n;i>=1;i--)        //第二次搜索从时间戳大的开始走找连通分量  
42         if(!vis[order[i]]){  
43             count++;        //连通分量个数  
44             dfst(order[i]);  
45         }  
46 }  
47   
48 void output(){  
49     int i,j,inzero=0,outzero=0;  
50     for(i=1;i<=n;i++){  
51         indegree[i]=outdegree[i]=0;  
52     }  
53     for(i=1;i<=n;i++)                //找连通分量入度与出度  
54         for(j=1;j<=n;j++)  
55             if(map[i][j] && belong[i]!=belong[j]){  
56                 indegree[belong[j]]++;  
57                 outdegree[belong[i]]++;  
58             }  
59     for(i=1;i<=count;i++){           //找入度与出度为0的点  
60         if(!indegree[i]) inzero++;  
61         if(!outdegree[i]) outzero++;  
62     }  
63   
64     if(count==1)                    //只有1个结点要特判  
65         printf("1\n0\n");  
66     else  
67         printf("%d\n%d\n",inzero,max(inzero,outzero));  
68 }  
69   
70 int main(){  
71     int i,a;  
72     while(~scanf("%d",&n)){  
73         for(i=1;i<=n;i++){  
74             while(scanf("%d",&a) && a) map[i][a]=1;  
75         }  
76         kosaraju();  
77         output();  
78     }  
79     return 0;  
80 }  

 

另一个用tarjan算法的实现

 1 /* 
 2 tarjan 
 3 Memory 224K 
 4 Time    0MS 
 5 */  
 6 #include <iostream>  
 7 using namespace std;  
 8 #define MAXV 110  
 9 #define min(a,b) (a>b?b:a)  
10 #define max(a,b) (a>b?a:b)  
11   
12 int n,map[MAXV][MAXV],outdegree[MAXV],indegree[MAXV];  
13 int dfn[MAXV];                                  //第一次访问的步数  
14 int low[MAXV];                                  //子树中最早的步数  
15 int stap[MAXV],stop;                            //模拟栈  
16 bool instack[MAXV];                             //是否在栈中  
17 int count;                                      //记录连通分量的个数  
18 int cnt;                                        //记录搜索步数  
19 int belong[MAXV];                               //属于哪个连通分量  
20   
21 void init(){  
22     count=stop=cnt=0;  
23     memset(instack,false,sizeof(instack));  
24     memset(map,0,sizeof(map));  
25     memset(dfn,0,sizeof(dfn));  
26 }  
27   
28 void tarjan(int x){  
29     int i;  
30     dfn[x]=low[x]=++cnt;  
31     stap[stop++]=x;  
32     instack[x]=true;  
33     for(i=1;i<=n;i++){  
34         if(!map[x][i]) continue;  
35         if(!dfn[i]){  
36             tarjan(i);  
37             low[x]=min(low[i],low[x]);  
38         }else if(instack[i])  
39             low[x]=min(dfn[i],low[x]);  
40         //与x相连,但是i已经被访问过,且还在栈中  
41         //用子树节点更新节点第一次出现的时间  
42     }  
43   
44     if(low[x]==dfn[x]){  
45         count++;  
46         while(1){  
47             int tmp=stap[--stop];  
48             belong[tmp]=count;  
49             instack[tmp]=false;  
50             if(tmp==x) break;  
51         }  
52     }  
53 }  
54   
55 void output(){  
56     int i,j,inzero=0,outzero=0;  
57     for(i=1;i<=n;i++){  
58         indegree[i]=outdegree[i]=0;  
59     }  
60     for(i=1;i<=n;i++)                //找连通分量入度与出度  
61         for(j=1;j<=n;j++)  
62             if(map[i][j] && belong[i]!=belong[j]){  
63                 indegree[belong[j]]++;  
64                 outdegree[belong[i]]++;  
65             }  
66     for(i=1;i<=count;i++){           //找入度与出度为0的点  
67         if(!indegree[i]) inzero++;  
68         if(!outdegree[i]) outzero++;  
69     }  
70   
71     if(count==1)                    //只有1个结点要特判  
72         printf("1\n0\n");  
73     else  
74         printf("%d\n%d\n",inzero,max(inzero,outzero));  
75 }  
76   
77 int main(){  
78     int i,a;  
79     while(~scanf("%d",&n)){  
80         init();  
81         for(i=1;i<=n;i++){  
82             while(scanf("%d",&a) && a) map[i][a]=1;  
83         }  
84         for(i=1;i<=n;i++)  
85             if(!dfn[i]) tarjan(i);  
86         output();  
87     }  
88     return 0;  
89 } 

 

posted @ 2017-12-18 21:58  LBNOQYX  阅读(104)  评论(0编辑  收藏  举报