• (转载) poj1236


    看到一篇挺好的代码,适合初学者,转载自 博主 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
    0
    ");  
    66     else  
    67         printf("%d
    %d
    ",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
    0
    ");  
    73     else  
    74         printf("%d
    %d
    ",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 } 
  • 相关阅读:
    内存管理3 Win32汇编语言056
    高级强制类型转换 C++快速入门37
    内存管理3 Win32汇编语言056
    密码学基础
    危险API的禁用列表
    危险API的禁用列表
    《那些年啊,那些事——一个程序员的奋斗史》——68
    《那些年啊,那些事——一个程序员的奋斗史》——68
    《那些年啊,那些事——一个程序员的奋斗史》——68
    春节期间停止更新
  • 原文地址:https://www.cnblogs.com/chaoswr/p/8059863.html
Copyright © 2020-2023  润新知