Description
Treeland是一个有n个城市组成的国家,其中一些城市之间有单向边连通。在这个国家中一共有n-1条路。我们知道,如果我们不考虑路的方向,那么我可以从任意城市到达任意城市。
最近,Treeland的总理Candy为了发展经济,想要从这n个城市中选择一个作为Treeland的首都,首都必须要能到达其他任意城市,这使得有些道路必须反向,付出的代价即需要反向的道路条数。
Candy想要选择一个城市作为首都,使得付出的代价最小。可能有多个城市满足条件,按编号从小到大输出。
Input
第一行,一个整数n,表示城市个数
接下来n-1行,每行两个整数x、y,表示城市x到城市y之间有一条单向路径
Output
第一行,一个整数k,花费的最小代价。
第二行若干个整数,中间用空格隔开,表示满足条件的城市编号。行末没有多余的空格。
SampleInput#1
3
2 1
2 3
SampleInput#2
4
1 4
2 4
3 4
SampleOutput#1
0
2
SampleOutput#2
2
1 2 3
思路
首先不考虑他的方向
它就变成了一棵树
把某个点当成根节点(首都)
然后把每一个点到达根节点(首都)的代价存起来
再然后深搜
遍历每一个点时
可以发现除了他经过的边
到达其他点的代价都与到达根节点(首都)的代价相同
然后换根,计算答案
#include<algorithm>
#include<iostream>
#include<cstdio>
using namespace std;
int h[400250], A[400250], T[400250], cr[400250];
int Ans, n, x, y, t;
struct whw
{
int w,h,k;
}wh[400250];
void Dfs(int k)
{
T[k] = 1;
for(int i = h[k]; i; i = wh[i].h)
if(!T[wh[i].w])
{
Dfs(wh[i].w);
A[k] += A[wh[i].w];
if(!wh[i].k) A[k]++;
}
T[k] = 0;
}
void init(int num, int k, int sum)
{
int tot = A[1] - sum + num * 2;
if (tot < Ans)
{
Ans = tot;
cr[0] = 0;
cr[++cr[0]] = k;
}
else if(tot == Ans) cr[++cr[0]] = k;
T[k] = 1;
for(int i = h[k]; i; i = wh[i].h)
if(!T[wh[i].w])
init(num + wh[i].k, wh[i].w, sum+1);
T[k] = 0;
}
int main()
{
scanf("%d", &n);
for(int i = 1; i < n; ++i)
{
scanf("%d%d", &x, &y);
wh[++t] = (whw){y, h[x], 1}, h[x] = t;
wh[++t] = (whw){x, h[y], 0}, h[y] = t;
}
Dfs(1);
Ans = 1e9;
init(0, 1, 0);
printf("%d\n", Ans);
sort(cr + 1, cr + 1 +cr[0]);
for(int i = 1; i <= cr[0]; ++i)
printf("%d ", cr[i]);
return 0;
}