soj 2012. King
http://soj.me/show_problem.php?pid=2012
KJ推荐的这道题,关于强联通分量的。这里主要是利用 Kosaraju 算法,
两次bfs求出强联通分量,第二次dfs2()主要是以第一次的ord的倒序进行dfs。
缩点,然后把原图变为一个新的DAG图,然后统计新的DAG图的入点为0的个数。
注意这里输出的是序号,不是个数。
#include <iostream> #include <cstdio> #include <algorithm> #include <vector> #include <string.h> #include <cmath> using namespace std; const int maxn = 1015; vector<int>adj[maxn]; vector<int>radj[maxn]; vector<int>DAG_adj[maxn]; vector<int>ord; int vis[maxn],g[maxn]; int n,cnt; char map[maxn][maxn]; int num[maxn]; int innum[maxn]; int outnum[maxn]; void dfs1(int u) { vis[u]=true; for(int i=0;i<adj[u].size();i++) { int v=adj[u][i]; if(!vis[v]) dfs1(v); } ord.push_back(u); } void dfs2(int u) { vis[u]=true; g[u]=cnt; for(int i=0;i<radj[u].size();i++) { int v=radj[u][i]; if(!vis[v]) dfs2(v); } } void Kosaraju() { ord.clear(); memset(vis,false,sizeof(vis)); for(int i=1;i<=n;i++) { if(!vis[i]) dfs1(i); } memset(vis,false,sizeof(vis)); cnt=0; for(int i=ord.size()-1;i>=0;i--) { if(!vis[ord[i]]) { cnt+=1; dfs2(ord[i]); } } } int main() { while(scanf("%d",&n)!=EOF) { for(int i=1;i<=n;i++) { adj[i].clear(); radj[i].clear(); DAG_adj[i].clear(); g[i]=-1; } for(int i=1;i<=n;i++) scanf("%s",map[i]+1); for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) { if(map[i][j]=='1') { adj[i].push_back(j); radj[j].push_back(i); } } } Kosaraju(); memset(num,0,sizeof(num)); for(int i=1;i<=n;i++) num[g[i]]+=1; for(int i=1;i<=n;i++) { for(int j=0;j<adj[i].size();j++) { int u=adj[i][j]; if(g[i]!=g[u]) DAG_adj[g[i]].push_back(g[u]); } } memset(innum,0,sizeof(innum)); memset(outnum,0,sizeof(outnum)); for(int i=1;i<=cnt;i++) { for(int j=0;j<DAG_adj[i].size();j++ ) { int u=DAG_adj[i][j]; innum[u]+=1; outnum[i]+=1; } } int zeronum=0; int ok=0; for(int i=1;i<=cnt;i++) { if(innum[i]==0) { zeronum+=1; ok=i; } if(zeronum>=2) break; } if(zeronum>=2) printf("-1\n"); else { for(int i=1;i<=n;i++) { if(g[i]==ok) { printf("%d\n",i); break; } } } } }