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;
}
}
}
}
}