标签:
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