poj1236 Network of Schools (强连通分量)

题目

一些学校联接在一个计算机网络上,学校之间存在软件支援协议,

每个学校都有它应支援的学校名单(A学校支援学校B,并不表示B学校一定支援学校A)。

当某校获得一个新软件时,无论是直接获得还是通过网络获得,

该校都应立即将这个软件通过网络传送给它应支援的学校。

因此,一个新软件若想让所有联接在网络上的学校都能使用,只需将其提供给一些学校即可。

1. 最少需要将一个新软件直接提供给多少个学校,才能使软件能够通过网络被传送到所有学校?

2.最少需要添加几条新的支援关系,使得将一个新软件提供给任何一个学校,所有学校都能通过网络获得该软件。

思路来源

https://www.cnblogs.com/TnT2333333/p/6875680.html

奎神

题解

求强连通分量,缩点。

第一问是零入度点个数;

第二问是Max(零入度点个数,零出度点个数)。

只有一个SCC时特判。

注意:

如果只用incnt==1和outcnt==1判一个SCC,

是无法区分一条链和一个点的情形的

所以只能用tot==1来判第二问

第二问的构造,可采用

从某个入度为0的点①出发,走到一个出度为0的点②,

然后将②连向下一个入度为0的点③,以此类推

代码

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn=105;
const int maxm=2e4+5;
int n,m,u,v;
int incnt,outcnt;//最后答案 出度为0点的个数 
int head[maxn],cnt;
int low[maxn],dfn[maxn],num;//最早非负祖先时间戳 时间戳 
int stack[maxn],top,now;//用数组模拟栈 栈顶 当前栈顶值 
int par[maxn],tot;//染色 颜色数 
bool In[maxn];//是否在栈中 
int in[maxn],out[maxn];//如果不在一个连通分量里 统计出度  
int sum[maxn];//每个连通分量里的点的个数 
struct edge
{
	int to,next;
}e[maxm];
void add(int u,int v)
{
	e[++cnt].to=v;
	e[cnt].next=head[u];
	head[u]=cnt;
}
void dfs(int u)
{
	low[u]=dfn[u]=++num;
	In[u]=1;
	stack[++top]=u;
	for(int i=head[u];i;i=e[i].next)
	{
		int v=e[i].to;
		if(!dfn[v])
		{
			dfs(v);
			low[u]=min(low[u],low[v]);
		}
		else if(In[v])
		{
			low[u]=min(low[u],dfn[v]);
		}
	}
	if(low[u]==dfn[u])//环的第一个点 
	{
		tot++;
		do
		{
			now=stack[top--];
			par[now]=tot;
			sum[tot]++; 
			In[now]=0; 
		}while(now!=u);
	}
}
void init()
{
	memset(head,0,sizeof head);
	memset(low,0,sizeof low);
	memset(dfn,0,sizeof dfn);
	memset(par,0,sizeof par);
	memset(sum,0,sizeof sum);
	memset(In,0,sizeof In);
	memset(in,0,sizeof in);
	memset(out,0,sizeof out); 
	cnt=num=top=tot=0;
	incnt=outcnt=0;
}
void solve()
{
	for(int i=1;i<=n;++i)
	if(!dfn[i])dfs(i);
	for(int u=1;u<=n;++u)
	{
		for(int i=head[u];i;i=e[i].next)
		{
			int v=e[i].to;//u->v的有向边 
			//不在同一个连通分量里
			if(par[u]!=par[v])
			out[par[u]]++,in[par[v]]++; 
		}
	} 
	for(int i=1;i<=tot;++i)//枚举连通分量 
	{
		if(!in[i])incnt++;
		if(!out[i])outcnt++;
	}
}
int main()
{
	while(~scanf("%d",&n))
	{
		init();
		for(int i=1;i<=n;++i)
		{
			int x;
			while(~scanf("%d",&x)&&x)
			add(i,x);
		}
		solve();
		if(tot==1)puts("1"),puts("0");//注意特判一个SCC 
		else printf("%d\n%d\n",incnt,max(incnt,outcnt));
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/Code92007/article/details/89041701
今日推荐