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;

				}

			}

		}

	}

}

你可能感兴趣的:(2012)