poj 1236 Network of Schools(强连通分量,缩点)

题意:机房有n个计算机,然后每个计算机连着k个点,现在要传输消息,问

1.你最多要传送消息给几个电脑,可以使机房的所有电脑都受到消息。

2.添加几条边可以是所有电脑都可以相互连接

思路:在一个强连通分量里的是所有电脑都可以相互收到消息,所以我们需要缩点,把原来的图缩成一个DAG,之后找入度为0的点,之后一个DAG需要添加几个边可以变成一个强连通分量呢,答案是max(入度为0的值,出度为0的值)。

上代码:

#include <stdio.h>
#include <algorithm>
#include <string.h>
#include <stack>
#include <iostream>
const int maxn = 100+10;
using namespace std;
struct node
{
	int to,nex;
}edg[maxn*maxn];
int n,cnt = 0 , scc = 0 , Index = 0;
int head[maxn],low[maxn],dfn[maxn],instack[maxn],belong[maxn] , in[maxn] , out[maxn];
void add(int u,int v)
{
	edg[cnt].to = v;
	edg[cnt].nex = head[u];
	head[u] = cnt++;
}
stack<int>S;
void tarjan(int x)
{
	Index++;
	low[x] = dfn[x] = Index; 
	S.push(x);
	instack[x] = 1;
	for(int i = head[x] ; i!=-1 ; i = edg[i].nex)
	{
		int v = edg[i].to;
		if(!dfn[v])
		{
			tarjan(v);
			low[x] = min(low[v],low[x]);
		}
		else if(instack[v])
		{
			low[x] = min(dfn[v],low[x]);
		}
	}
	if(low[x] == dfn[x])
	{
		++scc;
		int v;
		while(1)
		{
			v = S.top();
			belong[v] = scc;
			S.pop();
			instack[v] = 0;
			if(v == x) break;
		}
	}
}
int main()
{
	while(scanf("%d",&n)!=EOF)
	{
		while(!S.empty())S.pop();
		memset(instack,0,sizeof(instack));
		memset(belong,0,sizeof(belong));
		memset(low,0,sizeof(low));
		memset(dfn,0,sizeof(dfn));
		memset(head,-1,sizeof(head));
		memset(in,0,sizeof(in));
		memset(out,0,sizeof(out));
		int te;
		cnt = 0 ,scc = 0 , Index = 0;
		for(int i = 1 ; i <= n ; i++)
		{
			while(cin>>te)
			{
				if(te == 0) break;
				add(i,te);
			}
		}
		for(int i = 1 ; i <= n ; i++)
		{
			if(!dfn[i])
			{
				tarjan(i);
			}
		}
		for(int i = 1 ; i <= n ; i++)
		{
			for(int j = head[i] ; j!=-1 ; j = edg[j].nex)
			{
				int v = edg[j].to;
				if(belong[i]!=belong[v])
				{
					out[belong[i]]++;
					in[belong[v]] ++;
				}
			}
		}
		int ans1 = 0 ,ans2 = 0;
		for(int i = 1 ; i <= scc; i++)
		{
			if(!in[i])
			{
				ans1++;
			}
			if(!out[i]) ans2++;
		}
		if(scc <= 1)printf("1\n0\n");
		else printf("%d\n%d\n",ans1,max(ans1,ans2));

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值