网络协议

网络协议(net)

Description

出自 IOI 1996

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

任务a:

请编一个程序,根据学校间支援协议(各个学校的支援名单),计算最少需要将一个新软件直接提供给多少个学校,才能使软件通过网络被传送到所有学校;

任务b:

如果允许在原有支援协议上添加新的支援关系。则总可以形成一个新的协议,使得此时只需将一个新软件提供给任何一个学校,其他所有学校就都可以通过网络获得该软件。编程计算最少需要添加几条新的支援关系。

Input

第一行是一个正整数n(2<=n<=100),表示与网络连接的学校总数。 随后n行分别表示每个学校要支援的学校,即:i+1行表示第i号学校要支援的所有学校代号,最后以0结束。

如果一个学校不支援任何其他学校,相应行则会有一个0。一行中若有多个数字,数字之间以一个空格分隔。

Output

包含两行,第一行是一个正整数,表示任务a的解;第二行也是一个正整数,表示任务b的解。

Sample Input 1

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

Sample Output 1

1
2

题目大意:

强连通分量+缩点,a任务就是要找出缩点后的新图中出度为0的点的数量,任务b为入度点的数量,模板题,这里要注意特判全部连通的情况!

#include<bits/stdc++.h>

using namespace std;

const int maxn = 205;
int dfn[maxn],low[maxn];
int Stack[maxn],t[maxn],tt[maxn],in[maxn],out[maxn];
bool instack[maxn];
int n,tot,num,cnt;
vector<int>e[maxn];

void add_edge(int u , int v)
{
	e[u].push_back(v);
}

void Tar(int u)
{
	dfn[u] = low[u] = ++tot;
	Stack[++num] = u;
	instack[u] = true;
	for(int i = 0 ; i < e[u].size() ; i++)
	{
		int v = e[u][i];
		if(!dfn[v])
		{
			Tar(v);
			low[u] = min(low[u],low[v]);
		}
		else if(instack[v])
		{
			low[u] = min(low[u],dfn[v]);
		}
	}
	if(dfn[u] == low[u])
	{
		while(u != Stack[num])
		{
			tt[cnt]++;
			t[Stack[num]] = cnt;
			instack[Stack[num]] = false;
			num--;
		}
		t[Stack[num]] = cnt;
		tt[cnt]++;
		instack[Stack[num]] = false;
		num--;
		cnt++;
	}
}


int main()
{
	cin >> n;
	for(int i = 1 ; i <= n ; i++)
	{
		int v;
		while(cin >> v)
		{
			if(v)
				add_edge(i,v);
			else
				break;
		} 
	}
	for(int i = 1 ; i <= n ; i++)
	{
		if(!dfn[i])
			Tar(i);
	}
	for(int i = 1 ; i <= n ; i++)
	{
		for(int j = 0 ; j < e[i].size() ; j++)
		{
			int u = i , v = e[u][j];
			if(t[u] != t[v])
			{
				out[t[u]]++;
				in[t[v]]++;
			}
				
		}
	}
	int suma = 0 , sumb = 0;
	if(cnt == 1)
	{
		cout << "1\n0" << endl;
		return 0;
	}
	for(int i = 0 ; i < cnt ; i++)
	{
		if(!out[i])
			suma++;
		if(!in[i])
			sumb++;
	}
	cout << sumb << "\n" << max(sumb,suma) << endl;
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

柠檬ya

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值