POJ1236
题解:
-
task A:给出多少个点,能传遍所有的点。求入度为0的点的个数
-
task B:加上多少个点,才能成为强连通图。即求max(sum(outdegree == 0),sum(indegree == 0))。因为强连通图每个点必须要有出度和入度,所以把度为0的都补上。
-
当原图已经为强连通图时,要特判为1。
代码:
#include <cstring>
#include <algorithm>
#include <iostream>
#include <cstdio>
#include <stack>
#include <vector>
using namespace std;
int const N = 100 + 10;
vector<int>G[N];
int n,cnt,scc,pre[N],lowlink[N],sccno[N];
int in[N],out[N];
stack<int>st;
void Init(){
for(int i=1;i<=n;i++){
G[i].clear();
int tmp;
while(cin>>tmp && tmp)
G[i].push_back(tmp);
}
}
void dfs(int u){
pre[u] = lowlink[u] = ++cnt;
st.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[v],lowlink[u]);
}else if(!sccno[v]){
lowlink[u] = min(lowlink[u],pre[v]);
}
}
if(pre[u] == lowlink[u]){
scc++;
while(1){
int x = st.top(); st.pop();
sccno[x]= scc;
if(x == u) break;
}
}
}
void Tarjain(){
cnt = scc = 0;
while(!st.empty()) st.pop();
memset(pre,0,sizeof(pre));
memset(sccno,0,sizeof(sccno));
for(int i=1;i<=n;i++)
if(!pre[i]) dfs(i);
memset(in,0,sizeof(in));
memset(out,0,sizeof(out));
for(int i=1;i<=n;i++){
for(int j=0;j<G[i].size();j++){
int v = G[i][j];
if(sccno[i] != sccno[v]) out[sccno[i]]++, in[sccno[v]]++;
}
}
int s1 = 0, s2 = 0;
for(int i=1;i<=scc;i++){
if(!out[i]) s1++;
if(!in[i]) s2++;
}
if(scc == 1){
printf("%d\n%d\n",1,0);
return;
}else printf("%d\n%d\n",s2,max(s1,s2));
}
int main(){
while(cin>>n){
Init();
Tarjain();
}
}