【题目链接】 http://poj.org/problem?id=1236
【题目大意】
给出一张有向图,问需要从几个起点出发才能遍历全图,
如果要求从任何一个点出发都能遍历全图,那么最少需要增加几条边
【题解】
先求出SCC,那么对于对于第一问,就是入度为0的SCC数量,
第二问是入度为0和出度为0的SCC数量较大的一个。
【代码】
#include <cstdio> #include <algorithm> #include <vector> #include <cstring> using namespace std; const int MAX_V=10000; int V; //顶点数 vector<int> G[MAX_V]; //图的邻接表表示 vector<int> rG[MAX_V]; //反向图 vector<int> vs; //后序遍历 bool used[MAX_V]; int cmp[MAX_V]; //所属强连通分量的拓扑序 void add_edge(int from,int to){ G[from].push_back(to); rG[to].push_back(from); } void dfs(int v){ used[v]=1; for(int i=0;i<G[v].size();i++){ if(!used[G[v][i]])dfs(G[v][i]); }vs.push_back(v); } void rdfs(int v,int k){ used[v]=1; cmp[v]=k; for(int i=0;i<rG[v].size();i++){ if(!used[rG[v][i]])rdfs(rG[v][i],k); } } int scc(){ memset(used,0,sizeof(used)); vs.clear(); for(int v=0;v<V;v++){if(!used[v])dfs(v);} memset(used,0,sizeof(used)); int k=0; for(int i=vs.size()-1;i>=0;i--){ if(!used[vs[i]])rdfs(vs[i],k++); }return k; } const int MAX_M=50000; int N,M,x; int A[MAX_M],B[MAX_M]; int in[MAX_V],out[MAX_V],NO_IN,NO_OUT; void solve(){ V=N; for(int i=0;i<V;i++){ while(scanf("%d",&x),x){ add_edge(i,x-1); } } int n=scc(); if(n==1){puts("1 0");return;} //SCC个数为1的时候要特殊判断 memset(in,0,sizeof(in)); memset(out,0,sizeof(out)); for(int i=0;i<V;i++){ for(int j=0;j<G[i].size();j++){ if(cmp[i]!=cmp[G[i][j]]){ ++out[cmp[i]];++in[cmp[G[i][j]]]; } } }NO_IN=NO_OUT=0; for(int i=0;i<n;i++){ if(!in[i])NO_IN++; if(!out[i])NO_OUT++; } printf("%d %d ",NO_IN,max(NO_IN,NO_OUT)); } int main(){ while(~scanf("%d",&N)){ solve(); }return 0; }