第42题-[拓扑排序]Chocolate Milk

200 篇文章 7 订阅
8 篇文章 0 订阅

题目描述

FJ的牛奶生产和运输是一个复杂的过程,他用挤奶器给他的那么多头奶牛挤奶然后流入管道。 

每一个管道把一台挤奶器和一个可能连有一台或多台挤奶器的接口连接起来(这样几个管道里的牛奶就汇合了)。然后牛奶流入附加管道(连在各个接口之间的管道)直到流到中央管道,通向储存室。 然后这些牛奶又经历一个逆向的过程通过管道分流到各个牛奶桶,最后被运至市场。 

FJ发现对于牛奶来说有一种最多的方式从一个接口流到另一个接口。并且由于FJ是一个高效率的人,他需要确保每一个管道都有牛奶经过,也就是说,没有多余的管道。 

 

如果我们把每个挤奶机、接口和奶罐都看成一个节点,就共有 N 个节点,输入有序的节点对A_i和B_i,代表牛奶从A_i节点流到B_i节点,如果没有相对应的父节点,那就说明这是一个挤奶器,同样的如果没有对应的尾节点,则这是一个奶罐。 


FJ把这些节点编号为 1..N,这样表示牛奶只能从编号较小节点流到编号较大节点。也就是说有N-1个管道。 


这几天巧克力牛奶的需求量激增,所以FJ想要在某一个接口处安装一个巧克力混合器以得到巧克力牛奶,为了节约,FJ只买了一个巧克力混合器。所以他想把这个东西放到一个所有牛奶都能经过的接口,事实上,有这种接口存在。

 
编程帮助FJ找到这样的节点(注意:不能把巧克力混合器放在挤奶机里)。 

例如:这样的情况:
 
一看就知道,在6或者7可以装巧克力混合器。 

 

输入

第一行:一个整数N; 
第2..N行 :第i+1行用两个整数A_i 和 B_i,表示第i个管道的两端; 

 

输出

若干行,升序输出每一个可以安装混合器的节点。

样例输入

9
1 4
3 5
2 4
5 6
6 7
7 8
4 6
7 9

样例输出

6
7

提示

【数据规模】

对于40%的数据: 2≤N≤250;

对于50%的数据: 2≤N≤6,000;

对于100%的数据:2≤N≤100,000;1≤A_i<B_i≤N;

Code:

#if 0
7
1 2
2 3
3 4
4 5
5 6
5 7
#endif

#include <iostream>
#include <vector>
#include <queue>

#define SIZE 100001

using namespace std;

vector<int> v[SIZE];
queue<int> q;
int degree[SIZE], c[SIZE];

int main(void)
{
	int n, x, y, i, temp, temp2, tot = 0;
	
	scanf("%d", &n);
	for (i = 1; i < n; ++i)
	{
		scanf("%d%d", &x, &y);
		v[x].push_back(y);
		++degree[y];
	}
	for (i = 1; i < n; i++)
	{
		if (!degree[i])
		{
			degree[i] = -1;
			c[i] = 1;
			++tot;
			q.push(i);
		}
	}
	while (!q.empty())
	{
		temp = q.front();
		q.pop();
		if ((c[temp] == tot) && (v[temp].size() > 1))
		{
			continue;
		}
		for (i = 0; i < v[temp].size(); ++i)
		{
			temp2 = v[temp][i];
			--degree[temp2];
			c[temp2] += c[temp];
			if (!degree[temp2])
			{
				q.push(temp2);
			}
		}
	}
	
	for (i = 1; i <= n; i++)
	{
		if ((c[i] == tot) && (degree[i] != -1))
		{
			printf("%d\n", i);
		}
	}
	
	return 0;
}

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值