持续更新中。。。。
Network of Schools
http://poj.org/problem?id=1236
给你一个有向图,有环的
1.有个超级源点s,s最少连几个点时,可以从s走到图上任意一点
2.最少添加几条边可以把图变成一个强连通分量
ans1---缩点之后,入度为0 的点的个数
ans2----缩点后,max(入度为0的点,出度为0的点),因为可以挨个连接,连的边转一圈,建议自己画一画
记得特判一下
#include <iostream>
#include <vector>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <set>
#include<stack>
using namespace std;
typedef long long ll;
const int maxn = 2e5+11;
vector<int> G[maxn];
void add(int x,int y){
G[x].push_back(y);
}
int n;
int ans,clor[maxn],df;
int dfn[maxn],low[maxn];
stack<int>s;
int tarjan(int x){
s.push(x);
dfn[x] = low[x] = ++df;
for (int i = 0; i < G[x].size();i++){
int p = G[x][i];
if(!dfn[p]){
tarjan(p);
low[x] = min(low[x], low[p]);
}
else if(!clor[p]){
low[x] = min(low[x], dfn[p]);
}
}
if(low[x] == dfn[x]){
ans++;
while(1){
int a = s.top();
s.pop();
clor[a] = ans;
if(a == x) break;
}
}
return 0;
}
int in[maxn], ot[maxn];
int main(){
cin >> n;
int x;
for (int i = 1; i <= n;i++){
while(1){
cin >> x;
if(x == 0) break;
add(i, x);
}
}
for (int i = 1; i <= n;i++){
if(dfn[i] == 0){
tarjan(i);
}
}
for (int i = 1; i <= n;i++){
for (int j = 0; j < G[i].size();j++){
int p = G[i][j];
int x = clor[i];
int y = clor[p];
if(x != y){
//x---->y
in[y]++;
ot[x]++;
}
}
}
int a = 0, b = 0;
for (int i = 1; i <= ans; i++){
if(in[i] == 0) a++;
if(ot[i] == 0) b++;
}
if(ans == 1){
cout << 1 << endl;
cout << 0 << endl;
return 0;
}
cout << a << endl;
cout << max(a,b) << endl;
return 0;
}