标签:
Time Limit: 1000MS | Memory Limit: 10000K | |
Total Submissions: 13804 | Accepted: 5507 |
Description
Input
Output
Sample Input
5 2 4 3 0 4 5 0 0 0 1 0
Sample Output
1 2
Source
N(2<N<100)各学校之间有单向的网络,每个学校得到一套软件后,可以通过单向网络向周边的学校传输,问题1:初始至少需要向多少个学校发放软件,使得网络内所有的学校最终都能得到软件。2,至少需要添加几条传输线路(边),使任意向一个学校发放软件后,经过若干次传送,网络内所有的学校最终都能得到软件。
也就是:给定一个有向图,求:
1) 至少要选几个顶点,才能做到从这些顶点出发,可以到达全部顶点
2) 至少要加多少条边,才能使得从任何一个顶点出发,都能到达全部顶点
思路:先求出所有连通分量,将每个连通分量缩成一点,则形成一个有向无环图DAG。为题1的答案就是DAG中入度为0的点个数。问题2等价于在DAG中最少加几条边才能变成强连通。
要为每个入度为0的点加入边,为每个出度为0的点加出边,假设有n个入度为0的点,m个出度为0的点,则答案一定是min(n, m)。另外需要注意的是如果整个图只有一个强连通分支的时候,即缩点后只有一个点,则不需要加边,输出0。
/* ID: LinKArftc PROG: 1236.cpp LANG: C++ */ #include <map> #include <set> #include <cmath> #include <stack> #include <queue> #include <vector> #include <cstdio> #include <string> #include <utility> #include <cstdlib> #include <cstring> #include <iostream> #include <algorithm> using namespace std; #define eps 1e-8 #define randin srand((unsigned int)time(NULL)) #define input freopen("input.txt","r",stdin) #define debug(s) cout << "s = " << s << endl; #define outstars cout << "*************" << endl; const double PI = acos(-1.0); const double e = exp(1.0); const int inf = 0x3f3f3f3f; const int INF = 0x7fffffff; typedef long long ll; const int maxn = 110; const int maxm = 10010; struct Edge { int v, next; } edge[maxm]; int tot, head[maxn]; void init() { tot = 0; memset(head, -1, sizeof(head)); } void addedge(int u, int v) { edge[tot].v = v; edge[tot].next = head[u]; head[u] = tot ++; } int n, m; int dfn[maxn], low[maxn], ins[maxn], belong[maxn]; int scc, Time; stack <int> st; vector <int> vec[maxn]; void tarjan(int u) { dfn[u] = low[u] = ++ Time; int v; st.push(u); ins[u] = true; for (int i = head[u]; i + 1; i = edge[i].next) { v = edge[i].v; if (!dfn[v]) { tarjan(v); low[u] = min(low[u], low[v]); } else if (ins[v]) low[u] = min(low[u], low[v]); } if (low[u] == dfn[u]) { scc ++; do { v = st.top(); st.pop(); ins[v] = false; vec[scc].push_back(v); belong[v] = scc; } while (u != v); } } int indeg[maxn], outdeg[maxn]; int main() { //input; int v; while (~scanf("%d", &n)) { init(); for (int i = 1; i <= n; i ++) { while (~scanf("%d", &v) && v) { addedge(i, v); } } while (!st.empty()) st.pop(); for (int i = 1; i <= n; i ++) vec[i].clear(); memset(dfn, 0, sizeof(dfn)); memset(ins, 0, sizeof(ins)); Time = 0; scc = 0; for (int i = 1; i <= n; i ++) { if (!dfn[i]) tarjan(i); } memset(indeg, 0, sizeof(indeg)); memset(outdeg, 0, sizeof(outdeg)); for (int u = 1; u <= n; u ++) { for (int i = head[u]; i + 1; i = edge[i].next) { v = edge[i].v; if (belong[u] == belong[v]) continue; outdeg[belong[u]] ++; indeg[belong[v]] ++; } } int incnt = 0, outcnt = 0; for (int i = 1; i <= scc; i ++) { if (indeg[i] == 0) incnt ++; if (outdeg[i] == 0) outcnt ++; } printf("%d\n", incnt); if (scc == 1) printf("0\n"); else printf("%d\n", max(incnt, outcnt)); } return 0; }
POJ1236 (强连通分量缩点求入度为0和出度为0的分量个数)
标签:
原文地址:http://www.cnblogs.com/LinKArftc/p/4906036.html