旅行计划

某个国家有N个城市,编号0 至 N-1,他们之间用N - 1条道路连接,道路是双向行驶的,沿着道路你可以到达任何一个城市。你有一个旅行计划,这个计划是从编号K的城市出发,每天到达一个你没有去过的城市,并且旅途中经过的没有去过的城市尽可能的多(如果有2条路线,经过的没有去过的城市同样多,优先考虑编号最小的城市),直到所有城市都观光过一遍。现在给出城市之间的交通图T,以及出发地点K,你来设计一个旅行计划,满足上面的条件。例如:

 

(K = 2)

 

 

第1天 从2到0 (城市 1 和 0 变成去过的)

第2天 从0到6 (城市 4 和 6 变成去过的)

第3天 从6到3 (城市 3 变成去过的)

第4天 从3到5 (城市 5 变成去过的)

 

上图的输入数据为:0 1 2 2 1 4。共7个节点,除节点0之外,共6行数据。

第1个数0表示1到0有1条道路。

第2个数1表示2到1有1条道路。

Input

第1行:2个数N,K(1 <= N <= 50000, 0 <= K <= N - 1)
第2 - N + 1行:每行一个数,表示节点之间的道路。

Output

输出旅行的路线图,即每天到达的城市编号。

Input示例

7 2
0
1
2
2
1
4

Output示例

2
0
6
3
5

思路:

树形DP,依次找到叶子节点。将它们根据规则排序。

​

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
using namespace std;

const int MAXN = 1e5 + 10;

struct Node
{
    int to, prev;
} edge[MAXN];

int tot = 0;
int head[MAXN], deep[MAXN];

void add(int u, int v)
{
	tot++;
    edge[tot].to = v;
    edge[tot].prev = head[u];
    head[u] = tot;
}

struct Node2
{
    int num, depth, cnt;

    Node2(int n, int d, int c = 0) : num(n), depth(d), cnt(c) {}

    bool operator < (const Node2 &b) const
    {
        if (depth == b.depth)
        {
            return num < b.num;
        }
        return depth > b.depth;
    }
};

vector<Node2> vn2;

int pre[MAXN];

void dfs(int x, int pr)
{
    pre[x] = pr;
    bool flag = false;
    for (int i = head[x]; i > 0; i = edge[i].prev)
    {
        int v = edge[i].to;
        if (v == pr)
        {
            continue;
        }
        else
        {
            flag = true;
        }
        deep[v] = deep[x] + 1;
        dfs(v, x);
    }
    if (!flag)
    {
        vn2.push_back(Node2(x, deep[x]));
    }
}

bool cmp(Node2 a, Node2 b)
{
	if (a.cnt == b.cnt)
	{
		return a.num < b.num;
	}
    return a.cnt > b.cnt;
}

bool vis[MAXN];

int main()
{
    int n, k;
    cin >> n >> k;

    int v;
    for (int i = 1; i < n; i++)
    {
        cin >> v;
        add(v, i);
        add(i, v);
    }

    deep[k] = 1;
    vis[k] = true;
    dfs(k, -1);

    sort(vn2.begin(), vn2.end());           
    for (int i = 0; i < vn2.size(); i++)    
    {
        Node2 leaf = vn2[i];
        int num = leaf.num;
        int cnt = 0;
        while (num != -1)
        {
            if (!vis[num])
            {
                cnt++;
                vis[num] = true;
            }
            else
            {
                break;
            }
            num = pre[num];
        }
        vn2[i].cnt = cnt;
    }

    cout << k << endl;
    sort(vn2.begin(), vn2.end(), cmp);     
    for (int i = 0; i < vn2.size(); i++)
    {
        if (vn2[i].cnt)
        {
            cout << vn2[i].num << endl;
        }
    }

    return 0;
}

​

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值