【DFS】【树】Candy选首都(treeland)

DescriptionDescription

Treeland是一个有n个城市组成的国家,其中一些城市之间有单向边连通。在这个国家中一共有n-1条路。我们知道,如果我们不考虑路的方向,那么我可以从任意城市到达任意城市。
最近,Treeland的总理Candy为了发展经济,想要从这n个城市中选择一个作为Treeland的首都,首都必须要能到达其他任意城市,这使得有些道路必须反向,付出的代价即需要反向的道路条数。
Candy想要选择一个城市作为首都,使得付出的代价最小。可能有多个城市满足条件,按编号从小到大输出。

InputInput

第一行,一个整数n,表示城市个数
接下来n-1行,每行两个整数x、y,表示城市x到城市y之间有一条单向路径

OutputOutput

第一行,一个整数k,花费的最小代价。
第二行若干个整数,中间用空格隔开,表示满足条件的城市编号。行末没有多余的空格。

SampleSample InputInput

Sample Input1:
3
2 1
2 3

Sample Input2:
4
1 4
2 4
3 4

SampleSample OutputOutput

Sample Output1:
0
2

Sample Output2:
2
1 2 3

HintHint

对于70%的数据 n<=5000
对于100%的数据 n<=2*10^5

TrainTrain ofof ThoughtThought

存下一条边改变和不改变的情况,然后对于一个点进行深搜,求出有多少条边需要改变才能使其变为一棵树,然后再换根,继续求就好了

CodeCode

#include<cstdio>
#include<iostream>
#include<algorithm>

using namespace std;
int ans, n, t;
int st[200005], h[200005], s[200005];
bool meet[200005];

struct Tree
{
	int to, next, change;
}tree[400005];

void dfs(int x)
{
	meet[x] = true;
	for (int i = h[x]; i; i = tree[i].next)
	{
		if (!meet[tree[i].to]) {
			dfs(tree[i].to); 
			s[x] += s[tree[i].to];//统计儿子的答案
			if (tree[i].change == 0) s[x]++;//改变的统计
		}
	}
	meet[x] = false;
}

void Count(int num, int x, int dep)
{
	int pp = dep - num, ppx = num;//pp为从根到当前点,需要改变多少条边,ppx则为反义
	int sum = s[1] - pp + ppx;//求出当前换点后的代价 
	if (sum < ans)
	{
		ans = sum;
		st[0] = 0;
		st[++st[0]] = x;//st为题目要求的答案序列
	}//更新答案
	else if (sum == ans)
		st[++st[0]] = x;
	meet[x] = true;
	for (int i = h[x]; i; i = tree[i].next)
		if (!meet[tree[i].to])
			Count(num + tree[i].change, tree[i].to, dep + 1);
	meet[x] = false;
}

int main()
{
	scanf("%d", &n);
	for (int i = 1, x, y; i < n; ++i)
	{
		scanf("%d%d", &x, &y);
		tree[++t] = (Tree) {y, h[x], 1}; h[x] = t;
		tree[++t] = (Tree) {x, h[y], 0}; h[y] = t;
	}
	ans = 1e9;
	dfs(1);
	Count(0, 1, 0);
	printf("%d\n", ans);
	sort(st + 1, st + 1 + st[0]);
	for (int i = 1; i <= st[0]; ++i)
		printf("%d ", st[i]);
} 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章