SSLOJ 1393 Candy选首都[treeland]
Description–
Treeland是一个有n个城市组成的国家,其中一些城市之间有单向边连通。在这个国家中一共有n-1条路。我们知道,如果我们不考虑路的方向,那么我可以从任意城市到达任意城市。
最近,Treeland的总理Candy为了发展经济,想要从这n个城市中选择一个作为Treeland的首都,首都必须要能到达其他任意城市,这使得有些道路必须反向,付出的代价即需要反向的道路条数。
Candy想要选择一个城市作为首都,使得付出的代价最小。可能有多个城市满足条件,按编号从小到大输出。
Input–
第一行,一个整数n,表示城市个数
接下来n-1行,每行两个整数x、y,表示城市x到城市y之间有一条单向路径
Output–
第一行,一个整数k,花费的最小代价。
第二行若干个整数,中间用空格隔开,表示满足条件的城市编号。行末没有多余的空格。
Sample Input–
Sample Input1:
3
2 1
2 3
Sample Input2:
4
1 4
2 4
3 4
Sample Output–
Sample Output1:
0
2
Sample Output2:
2
1 2 3
说明–
对于70%的数据 n<=5000
对于100%的数据 n<=2*10^5
解题思路–
把这幅图强制转换成一棵树,然后,看标吧
代码–
#include<algorithm>
#include<iostream>
#include<cstdio>
using namespace std;
const int N = 200005;
int n, t, xx, yy, ans = N, l[N], s[N], ls[N];
bool pd[N];
struct ooo
{
int x, tag, next;
}f[2 * N];
void dfs(int z)
{
pd[z] = 1;
for (int i = ls[z]; i; i = f[i].next)
if (!pd[f[i].x])
{
dfs(f[i].x);
s[z] = s[z] + s[f[i].x] + f[i].tag;//s[z]表示以z为根的这棵树从z开始走需要的反转次数
}
pd[z] = 0;
}
void xxx(int lev, int y, int z)
{
pd[z] = 1;
int ss = s[1] - y + (lev - y);
if (ss == ans) l[++t] = z;
if (ss < ans)
ans = ss, t = 1, l[t] = z;
for (int i = ls[z]; i; i = f[i].next)
if (!pd[f[i].x])
xxx(lev + 1, y + f[i].tag, f[i].x);//y累计需要反转的条数
}
int main()
{
scanf("%d", &n);
for (int i = 1; i < n; ++i)
{
scanf("%d%d", &xx,&yy);
f[++t].x = yy, f[t].next = ls[xx], f[t].tag = 0, ls[xx] = t;//正常
f[++t].x = xx, f[t].next = ls[yy], f[t].tag = 1, ls[yy] = t;//需要反转
}
dfs(1); t = 0;
xxx(0, 0, 1);
sort(l + 1, l + t + 1);
printf("%d\n", ans);
for (int i = 1; i <= t; ++i)
printf("%d ", l[i]);
return 0;
}