标签:
Description
Input
Output
Sample Input
5 2 4 3 0 4 5 0 0 0 1 0
Sample Output
1 2
题目大意:给你n个学校,每个学校有一个接收表,表示城市i向表内城市都可以发送文件。现在要发送文件给所有学校,问题A:问你至少发给几个学校就可以通过学校间的发送,让所有学校都能收到文件。问题B:问你发个任意一个学校,要让所有学校都能收到文件,需要最少加多少条有向边。
解题思路:问题A,其实就是让求对于强连通分量缩点后,有多少个缩点的入度为0。问题B:其实就让你求至少加入多少条有向边,可以让原图形成强连通图。问题B,对于缩点,我们统计入度和出度。对于入度为0的,我们理论上应该给它加一条入边,对于出度为0的,我们应该给它加一条出边。但是要求最少加边数,那么我们就可以让入度为0的和出度为0的各取所需,即从出度为0的缩点向入度为0的缩点连一条边。对于最后可能会剩下的一个点,让他另外加一条边即可。那么我们的答案就很明显了,即max(入度为0的缩点个数,出度为0的缩点个数)。
#include<stdio.h> #include<algorithm> #include<string.h> #include<vector> #include<stack> #include<iostream> using namespace std; const int maxn = 210; vector<int>G[maxn]; int pre[maxn],lowlink[maxn],sccno[maxn],dfs_clock,scc_cnt; stack<int>S; int indeg[maxn], outdeg[maxn]; void dfs(int u){ pre[u] = lowlink[u] = ++dfs_clock; S.push(u); for(int i = 0; i < G[u].size(); i++){ int v = G[u][i]; if(!pre[v]){ dfs(v); lowlink[u] = min(lowlink[u],lowlink[v]); }else if(!sccno[v]){ lowlink[u] = min(lowlink[u],pre[v]); } } if(lowlink[u] == pre[u]){ scc_cnt++; for(;;){ int x = S.top(); S.pop(); sccno[x] = scc_cnt; if(x == u) break; } } } void find_scc(int n){ dfs_clock = scc_cnt = 0; memset(sccno,0,sizeof(sccno)); memset(pre,0,sizeof(pre)); for(int i = 1; i <= n; i++){ if(!pre[i]) dfs(i); } } int main(){ int n; scanf("%d",&n); for(int i = 1; i <= n; i++){ int v ; for(;;){ scanf("%d",&v); if(v == 0){ break; } G[i].push_back(v); } } find_scc(n); if(scc_cnt == 1){ puts("1"); puts("0"); }else{ int sccout, sccin; for(int i = 1; i <= n; ++i){ for(int j = 0; j < G[i].size(); j++){ int v = G[i][j]; sccout = sccno[i]; sccin = sccno[v]; if(sccout == sccin){ continue; } outdeg[sccout]++; indeg[sccin]++; } } int ans1 = 0, ans2 = 0; for(int i = 1; i <= scc_cnt; i++){ if(indeg[i] == 0){ ans1++; } if(outdeg[i] == 0){ ans2++; } } printf("%d\n%d\n",ans1,max(ans1,ans2)); } return 0; }
POJ 1236——Network of Schools——————【加边形成强连通图】
标签:
原文地址:http://www.cnblogs.com/chengsheng/p/4943677.html