SSLOJ·Candy选首都【DFS】

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;
} 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值