码迷,mamicode.com
首页 > Web开发 > 详细

POJ1236 (Network of Schools,Tarjan,强连通分量)

时间:2016-04-27 20:43:38      阅读:355      评论:0      收藏:0      [点我收藏+]

标签:

转载自:http://www.tuicool.com/articles/EnMFFja

原创:kuangbin

题意:

   一个有向图,求:

  1) 至少要选几个顶点,才能做到从这些顶点出发,可以到达全部顶点

  2) 至少要加多少条边,才能使得从任何一个顶点出发,都能到达全部顶点,即成为一个强连通分量

思路:

  求完强连通分量后,缩点,计算每个点的入度,出度。

   第一问的答案就是入度为零的点的个数,

   第二问就是max(n,m)  入度为零的个数为n, 出度为零的个数为m

思路详解:

     1. 求出所有强连通分量
     2. 每个强连通分量缩成一点,则形成一个有向无环图DAG。
     3. DAG上面有多少个入度为0的顶点,问题1的答案就是多少
在DAG上要加几条边,才能使得DAG变成强连通的,问题2的答案就是多少
加边的方法:
要为每个入度为0的点添加入边,为每个出度为0的点添加出边
假定有 n 个入度为0的点,m个出度为0的点,如何加边?
把所有入度为0的点编号 0,1,2,3,4 ....N -1
每次为一个编号为i的入度0点可达的出度0点,添加一条出边,连到编号为(i+1)%N 的那个出度0点,
这需要加n条边
若 m <= n,则
加了这n条边后,已经没有入度0点,则问题解决,一共加了n条边
若 m > n,则还有m-n个入度0点,则从这些点以外任取一点,和这些点都连上边,即可,这还需加m-n条边。
所以,max(m,n)就是第二个问题的解
此外:当只有一个强连通分支的时候,就是缩点后只有一个点,虽然入度出度为0的都有一个,但是实际上不需要增加清单的项了,所以答案是1,0;

Tarjan算法浅解:

技术分享                     技术分享

  1.过程:

    (1)dfn[i]表示dfs时达到顶点i的时间戳

        low[i]表示i所能直接或间接达到    时间最小的顶点(比如上图  3->1   low[3] = 1)

    (2)time初始化为0,在dfs遍历到u时,low[u]=dfn[u]=time++,u入栈

             扫描u的邻接顶点v,如果 v没有被访问则dfs(v);

              low[u]=min(low[u],low[v])

                如果邻接顶点在此次已经被扫描:即dfn[v] != 0 和 belong[v] == 0 , low[u] = min(low[u],dfn[v]);

      如果low[v]=dfn[v]时,栈里v以及v以上的顶点全部出栈,且刚刚出栈的就是一个极大强连通分量。

  2.大概原理:

    填坑......

代码:

 1 //#include<bits/stdc++.h>
 2 #include<vector>
 3 #include<algorithm>
 4 #include<cstring>
 5 #include<cstdio>
 6 #include<stack>
 7 using namespace std;
 8 typedef long long ll;
 9 
10 const int maxn = 100 + 10;
11 
12 vector<int> G[maxn];
13 int n,dfn[maxn],low[maxn],belong[maxn],dfs_clock,scc_cnt;
14 stack<int> S;
15 
16 /**
17 
18     Tarjan算法
19 
20 */
21 
22 void dfs(int u){
23     dfn[u] = low[u] = ++dfs_clock;
24     S.push(u);
25     for(int i = 0 ; i < G[u].size() ; i ++){
26         int v = G[u][i];
27         if(!dfn[v]){
28             dfs(v);
29             low[u] = min(low[u],low[v]);
30         }else if(!belong[v]){
31             low[u] = min(low[u],dfn[v]);
32         }
33     }
34     if(low[u] == dfn[u]){
35         scc_cnt++;
36         for(;;){
37             int x = S.top(); S.pop();
38             belong[x] = scc_cnt;
39             if(x == u) break;
40         }
41     }
42 }
43 
44 void scc(int n){
45     dfs_clock = scc_cnt = 0;
46     memset(dfn,0,sizeof(dfn));
47     memset(belong , 0 ,sizeof(belong));
48     for(int i = 0 ; i < n ; i ++)
49         if(!dfn[i]) dfs(i);
50 
51 }
52 
53 int main(){
54     int x;
55     while(scanf("%d",&n) != EOF && n){
56         for(int i = 0 ; i <= n ; i ++)  G[i].clear();
57         for(int i = 0 ; i < n ; i ++){
58             while(scanf("%d",&x),x){
59                 --x;
60                 G[i].push_back(x);
61             }
62         }
63         scc(n);
64         if(scc_cnt == 1){
65             printf("1\n0\n");
66             continue;
67         }
68         int in[maxn],out[maxn],in_tot = 0 , out_tot = 0;
69         memset(in,0,sizeof(in));
70         memset(out,0,sizeof(out));
71         for(int i = 0 ; i < n ; i ++){
72             for(int j = 0 ; j < G[i].size() ; j ++){
73                 int v = G[i][j];
74 /**
75     遍历每个点.
76         遍历与该点相连的点
77             判断两个点是否同一个连通分量
78             如果不是,则改变缩点后的出入度
79 
80 */
81                 if(belong[i] != belong[v]){
82                     out[ belong[i] ] ++;
83                     in [ belong[v] ] ++;
84                 }
85             }
86         }
87         for(int i = 1 ; i <= scc_cnt ; i ++){
88             if(!in[i]) in_tot++;
89             if(!out[i]) out_tot++;
90         }
91 
92         printf("%d\n%d\n",in_tot,max(in_tot,out_tot));
93     }
94     return 0;
95 }

 

POJ1236 (Network of Schools,Tarjan,强连通分量)

标签:

原文地址:http://www.cnblogs.com/zstu-jack/p/5440212.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!