POJ - 1236 Network of Schools(强连通缩点)

爷,独闯天下 提交于 2019-12-24 14:57:01

题目链接:点击查看

题目大意:一个学校连接在一个计算机网络上,学校之间存在软件支援协议,每个学校都有它应支援的学校名单(学校A支援学校B,并不表示学校B一定支援学校A)。当某校获得一个新软件时,无论是直接获得还是通过网络获得,该校都应立即将这个软件通过网络传送给它应支援的学校,因此,一个新软件若想让所有学校都能使用,只需将其提供给一些学校即可:

  1. 最少需要将一个新软件直接提供给多少个学校,才能使软件能够通过网络被传送到所有学校?
  2. 最少需要添加几条新的支援关系,使得将一个新软件提供给任何一个学校,其他所有学校就都可以通过网络获得该软件?

题目分析:题目给出的是有向图,对于这个题目而言,首先强连通缩一下点,这样每一个集合中的点;两两都可以互相到达,相对来说无法到达的就只有入度为0的点对应的集合了,统计一下有多少个入度为0的集合,就是第一问的答案了,对于第二问而言,为了让整个集合成为强连通图,我们必须让所有点的入度和出度都不为0,所以答案就是入度为0的集合的数量和出度为0的集合的数量中的较大值了,不过这个题目有个小坑需要特判一下,如果一开始整个图就是一个强联通图的话,那么答案需要输出1 0,而不是1 1

代码:

#include<iostream>
#include<cstdlib>
#include<string>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<climits>
#include<cmath>
#include<cctype>
#include<stack>
#include<queue>
#include<list>
#include<vector>
#include<set>
#include<map>
#include<sstream>
using namespace std;
    
typedef long long LL;
    
const int inf=0x3f3f3f3f;

const int N=110;
 
const int M=N*N;
 
struct Egde
{
	int to,next;
}edge1[M],edge2[M];
 
int head1[N],head2[N],low[N],dfn[N],c[N],Stack[N],num,cnt,cnt2,cnt1,dcc,n,m,top,in[N],out[N];
 
bool ins[N];

vector<int>scc[N];
 
void addedge1(int u,int v)
{
	edge1[cnt1].to=v;
	edge1[cnt1].next=head1[u];
	head1[u]=cnt1++;
}

void addedge2(int u,int v)
{
	edge2[cnt2].to=v;
	edge2[cnt2].next=head2[u];
	head2[u]=cnt2++;
}
 
void tarjan(int u)
{
	dfn[u]=low[u]=++num;
	Stack[++top]=u;
	ins[u]=true;
	for(int i=head1[u];i!=-1;i=edge1[i].next)
	{
		int v=edge1[i].to;
		if(!dfn[v])
		{
			tarjan(v);
			low[u]=min(low[u],low[v]);
		}
		else if(ins[v])
			low[u]=min(low[u],dfn[v]);
	}
	if(dfn[u]==low[u])
	{
		cnt++;
		int v;
		do
		{
			v=Stack[top--];
			ins[v]=false;
			c[v]=cnt;
			scc[cnt].push_back(v);
		}while(u!=v);
	}
}
 
void solve()
{
	for(int i=1;i<=n;i++)//缩点 
		if(!dfn[i])
			tarjan(i);
}
 
void build()//缩点+连边 
{
	solve();
	for(int i=1;i<=n;i++)
	{
		for(int j=head1[i];j!=-1;j=edge1[j].next)
		{
			int u=i;
			int v=edge1[j].to;
			if(c[u]!=c[v])
				addedge2(c[u],c[v]);
		}
	}
}

void init()
{
	for(int i=0;i<N;i++)
		scc[i].clear();
	top=cnt=cnt1=cnt2=num=dcc=0;
	memset(head2,-1,sizeof(head2));
	memset(head1,-1,sizeof(head1));
	memset(low,0,sizeof(low));
	memset(dfn,0,sizeof(dfn));
	memset(c,0,sizeof(c));
	memset(ins,false,sizeof(ins));
	memset(in,0,sizeof(in));
	memset(out,0,sizeof(out));
}

int main()
{
//  freopen("input.txt","r",stdin);
//  ios::sync_with_stdio(false);
	while(scanf("%d",&n)!=EOF)
	{
		init();
		for(int i=1;i<=n;i++)
		{
			int to;
			while(scanf("%d",&to)!=EOF&&to)
				addedge1(i,to);
		}
		build();
		for(int i=1;i<=cnt;i++)
		{
			for(int j=head2[i];j!=-1;j=edge2[j].next)
			{
				int u=i;
				int v=edge2[j].to;
				if(u!=v)
				{
					in[v]++;
					out[u]++;
				}
			}
		}
		int ans1=0,ans2=0;
		for(int i=1;i<=cnt;i++)
		{
			if(!in[i])
				ans1++;
			if(!out[i])
				ans2++;
		}
		if(cnt>1)
			printf("%d\n%d\n",ans1,max(ans1,ans2));
		else
			printf("1\n0\n");
	}
	
	
	
	
    
    
    
    
 
        
        
        
         
        
    return 0;
}

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!