【POJ 1236】Network of Schools(tarjan算法)

43 篇文章 0 订阅
13 篇文章 0 订阅
Network of Schools
Time Limit: 1000MS Memory Limit: 10000K
Total Submissions: 15071 Accepted: 5992

Description

A number of schools are connected to a computer network. Agreements have been developed among those schools: each school maintains a list of schools to which it distributes software (the “receiving schools”). Note that if B is in the distribution list of school A, then A does not necessarily appear in the list of school B 
You are to write a program that computes the minimal number of schools that must receive a copy of the new software in order for the software to reach all schools in the network according to the agreement (Subtask A). As a further task, we want to ensure that by sending the copy of new software to an arbitrary school, this software will reach all schools in the network. To achieve this goal we may have to extend the lists of receivers by new members. Compute the minimal number of extensions that have to be made so that whatever school we send the new software to, it will reach all other schools (Subtask B). One extension means introducing one new member into the list of receivers of one school. 

Input

The first line contains an integer N: the number of schools in the network (2 <= N <= 100). The schools are identified by the first N positive integers. Each of the next N lines describes a list of receivers. The line i+1 contains the identifiers of the receivers of school i. Each list ends with a 0. An empty list contains a 0 alone in the line.

Output

Your program should write two lines to the standard output. The first line should contain one positive integer: the solution of subtask A. The second line should contain the solution of subtask B.

Sample Input

5
2 4 3 0
4 5 0
0
0
1 0

Sample Output

1
2

Source

[Submit]   [Go Back]   [Status]   [Discuss]

Home Page   Go Back  To top


[题意][有N个学校...每个学校可能向几个学校进行数据传输(单向的)问..至少需要把一个文件给几个学校可以使给的N个学校都收到文件...再问在加几个通信线路可以使各个学校之间都能直接或间接的传递文件]
【题解】【一个强连通分量里的所有点可以互相传输,那么这道题实际上就是在求当前图中有几个强连通分量,第二问是问还需再加入几条边,也就是说还需要几条边把剩下的点连起来。因为一个强连通分量必然不需要考虑,所以考虑把每个强连通分量缩成一个点来处理】
【求强连通分量要用到tarjan算法】

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int a[100500],nxt[100500],p[110],tot;//next数组存有向图
int dft[110],dis[110],root,cnt;//dst表示dfs到当前点的时间,dis表示当前点可到达的点中时间最小的 
int in[110],out[110],f[110],n;//点的入度和出度,f是缩点后的每个点的序号 
int d[110],top;//栈
bool vis[110];//记录每个元素是否在栈中 

inline void add(int x,int y)
{
	tot++; a[tot]=y; nxt[tot]=p[x]; p[x]=tot;
}

void tarjan(int u)
{
	dft[u]=dis[u]=++cnt;
	d[++top]=u; vis[u]=1;
	int v=p[u];
	while(v>=0)
	 {
	 	if(!dft[a[v]])
	   {
	  	 tarjan(a[v]);
	  	 dis[u]=min(dis[u],dis[a[v]]);
	   }
	  else
	    if(vis[a[v]]&&dis[u]>dft[a[v]]) dis[u]=dft[a[v]];
	  v=nxt[v];
	 }
	int b=a[p[u]];
	if(dft[u]==dis[u])//说明找到一个强连通分量 
	 {
	 	++root;//缩点 
	 	do{
	 		b=d[top--];
	 		vis[b]=false;
	 		f[b]=root;
		 }while(u!=b);//把当前强连通分量里包含的所有点缩成一个点来代替 
	 }
	return;
}//查找强连通分量 
void solve()
{
	root=top=cnt=0;
	memset(dft,0,sizeof(dft));
	memset(vis,0,sizeof(vis));
	for(int i=1;i<=n;++i)
	 if(!dft[i]) tarjan(i);
	return;
}//dfs找所有的强连通分量,每次从一个没有搜索过的点开始
 
void count()
{
	memset(in,0,sizeof(in));
	memset(out,0,sizeof(out));
	for(int i=1;i<=n;++i)
	 {
	 	int u=p[i];
	 	while(u>=0)
	 	 {
	 	 	if(f[i]!=f[a[u]]) 
	 	 	   out[f[i]]++,in[f[a[u]]]--;
	 	 	u=nxt[u];
		  }
	 }
	return;
}//缩点后,看还有几个点不属于强连通分量,则统计入度和出度,以便于后面计算要新加几条边 

int main()
{
	int i,j;
	while((scanf("%d",&n)==1)&&n) 
	 {
	    tot=0;
		memset(nxt,-1,sizeof(nxt));
	    memset(p,-1,sizeof(p));
		int b;
	 	for(i=1;i<=n;++i)
	 	 while((scanf("%d",&b)==1)&&b) add(i,b);
	 	solve();
	 	if(root==1) {printf("1\n0\n"); continue;}//如果缩完后就剩下一个点,即不需要再添边,直接输出即可 
	 	count();
	 	int inr=0,outr=0;
	 	for(i=1;i<=root;++i)
		 {
		 	if(!in[i]) inr++;
		 	if(!out[i]) outr++;
		  } //看缩点后有几个单独的点,就要新加几条边 
		printf("%d\n%d\n",inr,max(inr,outr));
	  } 
	return 0;  
 } 
(Tarjan算法见上一篇博文)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值