给我们一个有向图,有两个问题
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 0 "); 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 ", cnt1); 112 printf("%d ", max(cnt1, cnt2)); 113 } 114 return 0; 115 }