Network of Schools poj 1236
持续更新中。。。。
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; }
寻找真正的热爱