POJ 1236-Network of Schools(tarjan缩点)
传送门qwq:http://poj.org/problem?id=1236
题目大意:
有n(2<=n<=100)个学校,学校之间有单向网络,一个学校在得到软件之后可以顺着单向网络向其他学校传输
输入给出每个学校可以向其他学校传输的传输列表
1.初始时至少几个学校得到该软件才能使得网络内所有学校都收到该软件
2.至少添加几条边,才能使得向网络中任意一个学校发送该软件,最终能传遍网络中每一个学校
思路:
首先,一个学校能传到的所有学校肯定是在一个联通分量里的,首先用一下tarjan进行缩点,缩点之后再统计
根据缩点之后的图的出入度,对于入度为零的点,是需要初始时发送的学校,至于添加的边数,则是出度为零
的点数和入度为零的点数中大的那个
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
using namespace std;
const int N = 109;
int n,t,num,top;
int dfn[N],low[N],du1[N],du2[N],id[N];
int Stack[N],instack[N];
vector<int>q[N];
//tarjan算法,复杂度O(n + m)
void tarjan(int u)
{
dfn[u] = low[u] = ++t;
Stack[++top] = u;
instack[u] = 1;
for(int i = 0; i <q[u].size(); i++){
int v = q[u][i];
if(!dfn[v]){
tarjan(v);
low[u] = min(low[u],low[v]);
} else if(instack[v]){
low[u] = min(low[u],dfn[v]);
}
}
if(dfn[u] == low[u]){//此时出现新的联通分量
num++;
int vv;
do{
vv = Stack[top--];
instack[vv] = 0;
id[vv] = num;//将在一个连通分量中的点缩点
}while(vv != u);
}
}
int main()
{
// freopen("D:\\test\\in.txt","r+",stdin);
ios::sync_with_stdio(false);
cin >> n;
for(int i = 1; i <= n; i++){
int x;
while(cin >> x && x)q[i].push_back(x);
}
for(int i = 1; i <= n; i++)
if(!dfn[i])tarjan(i);
if(num == 1) return cout << 1 << endl << 0 << endl,0;//只有1个连通分量时特判
for(int i = 1; i <= n; i++){
for(int j = 0; j < q[i].size(); j++){
int v = q[i][j];
if(id[i] != id[v]){
du1[id[i]]++;
du2[id[v]]++;
}
}
}
int ans1 = 0,ans2 = 0;
for(int i = 1; i <= num; i++){
if(du1[i] == 0)ans1++;
if(du2[i] == 0)ans2++;
}
cout << ans2 << endl << max(ans1,ans2) << endl;
return 0;
}