poj1236 有向图加边变成强连通图

给我们一个有向图,有两个问题

1、最少要给多少个点发消息,才能使得所有的点都收到消息(消息可以随边传递)

2、最少需要多少条边才能使得图变成强连通图

 

对于一个强连通分量,可以当做一个点来考虑,所以我们可以缩点,然后得到DAG图,

那么对于第一个问,即是入度为0的点有多少个,因为入度为0的点无法收到消息。

对于第二问,只要加max(s1,s2)条边,就能使得DAG变成强连通图,  s1表示入度为0的点的个数,s2表示出度为0的点的个数

设s1 > s2, 那么首先加s2条边,这s2条边连接的是入度为0和出度为0的点,

然后剩下s1-s2个入度为0的点, 那么随便加s1-s2条边即可。

 

  1 #pragma warning(disable:4996)
  2 #pragma comment(linker, "/STACK:1024000000,1024000000")
  3 #include <stdio.h>
  4 #include <string.h>
  5 #include <time.h>
  6 #include <math.h>
  7 #include <map>
  8 #include <set>
  9 #include <queue>
 10 #include <stack>
 11 #include <vector>
 12 #include <bitset>
 13 #include <algorithm>
 14 #include <iostream>
 15 #include <string>
 16 #include <functional>
 17 #include <iostream>
 18 typedef __int64 LL;
 19 const int INF = 1 << 30;
 20 using namespace std;
 21 /*
 22 考虑如果是的一个有向图,变成连通图,
 23 将强联通分量缩成一个点,
 24 然后,如果某一个联通分量和其他的联通分量没有边,那么要加两条边,如果只有一条边
 25 那么只要加1条边
 26 */
 27 const int N = 100 + 10;
 28 int dfn[N], low[N], sccno[N], dfs_clock, cnt;
 29 stack<int> st;
 30 vector<int> g[N];
 31 
 32 void tarjan(int u, int fa)
 33 {
 34     dfn[u] = low[u] = ++dfs_clock;
 35     st.push(u);
 36     for (int i = 0; i<g[u].size(); ++i)
 37     {
 38         int v = g[u][i];
 39         if (dfn[v] == 0)
 40         {
 41             tarjan(v, u);
 42             low[u] = min(low[u], low[v]);
 43         }
 44         else if (sccno[v] == 0)//因为有向图存在横插边,不能用横插边来更新low[u]
 45         {
 46             low[u] = min(low[u], low[v]);
 47         }
 48     }
 49     //同样,因为强连通分量可以分布在根结点的两个分支上,所以在递归返回的时候调用
 50     if (low[u] == dfn[u])
 51     {
 52         cnt++;
 53         for (;;)
 54         {
 55             int x = st.top();
 56             st.pop();
 57             sccno[x] = cnt;
 58             if (x == u)
 59                 break;
 60         }
 61     }
 62 }
 63 bool in[N], out[N];
 64 int main()
 65 {    
 66     
 67     int n;
 68     while (scanf("%d", &n) != EOF)
 69     {
 70         dfs_clock = cnt = 0;
 71         while (!st.empty()) st.pop();
 72         for (int i = 1;i <= n;++i)
 73         {
 74             sccno[i] = 0;
 75             g[i].clear();
 76             low[i] = dfn[i] = 0;
 77             in[i] = out[i] = false;
 78         }
 79         for (int i = 1;i <= n;++i)
 80         {
 81             int u = i, v;
 82             while (scanf("%d", &v), v)
 83                 g[u].push_back(v);
 84         }
 85         for (int i = 1;i <= n;++i)
 86         {
 87             if (dfn[i] == 0)
 88                 tarjan(i, -1);
 89         }
 90         for (int i = 1;i <= n;++i)
 91         {
 92             for (int j = 0;j < g[i].size();++j)
 93             {
 94                 int v = g[i][j];
 95                 if (sccno[i] == sccno[v]) continue;
 96                 out[sccno[i]] = true;
 97                 in[sccno[v]] = true;
 98             }
 99         }
100         if (cnt == 1)
101         {
102             printf("1\n0\n");
103             continue;
104         }
105         int cnt1 = 0, cnt2 = 0;
106         for (int i = 1;i <= cnt;++i)
107         {
108             if (!in[i]) cnt1++;
109             if (!out[i]) cnt2++;
110         }
111         printf("%d\n", cnt1);
112         printf("%d\n", max(cnt1, cnt2));
113     }
114     return 0;
115 }

 

posted @ 2015-09-09 15:19  justPassBy  阅读(1756)  评论(0编辑  收藏  举报