POJ-1236-Network of Schools

POJ-1236-Network of Schools

http://poj.org/problem?id=1236

给一个有向图,问题1:最少从多少个点开始搜索能访问到图所有点,问题2:至少加几条边才能使从任一点搜索即能访问所有点

问题1的答案应该为入度为0的点的个数

问题2的答案即为入度为0的点和出度为0的点个数多的那个

Kosaraju_Algorithm:

step1:对原图G进行深度优先遍历,记录每个节点的离开时间。

step2:选择具有最晚离开时间的顶点,对反图GT进行遍历,删除能够遍历到的顶点,这些顶点构成一个强连通分量。

step3:如果还有顶点没有删除,继续step2,否则算法结束

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define M 150
int Max(int a,int b)
{
	return a>b?a:b;
}
int map[M][M];
int vis[M],order[M],belong[M],indegree[M],outdegree[M];
int n,num,count;
void dfs(int x)
{
	int i;
	vis[x]=1;
	for(i=1;i<=n;i++)
	if(map[x][i]&&!vis[i])
	dfs(i);
	order[++num]=x;
}
void dfst(int x)
{
	int i;
	belong[x]=count;  //记录结点属于哪个连通分量
	vis[x]=1;
	for(i=1;i<=n;i++)
	if(!vis[i]&&map[i][x])
	dfst(i);
}
void solve()
{
	int i;
	memset(vis,0,sizeof(vis));
	num=count=0;
	for(i=1;i<=n;i++)  //第一次搜索将时间戳从小到大排序
	if(!vis[i])
	dfs(i);
	memset(vis,0,sizeof(vis));
	for(i=n;i>=1;i--) //第二次搜索从时间戳大的开始走连通分量
	if(!vis[order[i]])
	{
		count++;  //连通分量数
		dfst(order[i]);
	}
}
void output()
{
	int i,j,inzero=0,outzero=0;
	for(i=1;i<=n;i++)
	indegree[i]=outdegree[i]=0;
	for(i=1;i<=n;i++)   //连通分量入度和出度
	for(j=1;j<=n;j++)
	if(map[i][j]&&belong[i]!=belong[j])
	{
		indegree[belong[j]]++;
		outdegree[belong[i]]++;
	}
	for(i=1;i<=count;i++)   //找入度与出度为0的点
	{
		if(!indegree[i])
		inzero++;
		if(!outdegree[i])
		outzero++;
	}
	if(count==1)
	printf("1\n0\n");
	else 
	printf("%d\n%d\n",inzero,Max(inzero,outzero));
}
int main()
{
	int i,a;
	while(scanf("%d",&n)!=EOF)
	{
		for(i=1;i<=n;i++)
		{
			while(scanf("%d",&a),a)
			map[i][a]=1;
		}
		solve();
		output();
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值