描述
题解
通过题意,我们可以清晰的知道,每天到达的结点一定是叶子结点,所以我们先 dfs 遍历一遍树,将说有的叶子结点x
入vn2
,这里我们附带还要入一个叶子节点的深度d
,为了保证未经过的城市最多,当然,光这样还是无法保证未经过的城市最多,因为不同的叶子结点到根节点的路径会有重合,所以我们需要从所有叶子结点开始向前访问一遍(访问之前需要进行一次排序,保证未经过的城市最多,同样多时,保证编号最小),求出有多少个未访问过的结点cnt
,同样存入vn2
中。
最后,我们只需要将vn2
根据cnt
的大小进行一下排序输出即可。说到底,这里是一个贪心
,搞不懂话题为啥是树形DP
,难道是为了迷惑我们?
代码
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
#define pb push_back
using namespace std;
const int MAXN = 1e5 + 10;
struct node
{
int to, next;
} edge[MAXN];
int tot = 0;
int head[MAXN], deep[MAXN];
void add(int u, int v)
{
edge[++tot].to = v;
edge[tot].next = head[u];
head[u] = tot;
}
struct node2
{
int x, d, cnt;
node2(int x_, int d_, int cnt_ = 0) : x(x_), d(d_), cnt(cnt_) {}
bool operator < (const node2 &b) const
{
return d > b.d || (d == b.d && x < b.x);
}
};
vector<node2> vn2;
int pre[MAXN];
// 遍历树,存储 pre[],将叶子结点与其深度入 vn2
void dfs(int x, int pr)
{
pre[x] = pr;
bool flag = false;
for (int i = head[x]; i; i = edge[i].next)
{
int v = edge[i].to;
if (v == pr)
{
continue;
}
else
{
flag = true;
}
deep[v] = deep[x] + 1;
dfs(v, x);
}
if (!flag)
{
vn2.pb(node2(x, deep[x]));
}
}
bool cmp(node2 a, node2 b)
{
return a.cnt > b.cnt || (a.cnt == b.cnt && a.x < b.x);
}
bool vis[MAXN];
int main()
{
int N, K;
cin >> N >> K;
int v;
for (int i = 1; i < N; i++)
{
scanf("%d", &v);
add(v, i);
add(i, v);
}
deep[K] = 1;
vis[K] = 1;
dfs(K, -1);
sort(vn2.begin(), vn2.end()); // 根据深度从大到小排序
for (int i = 0; i < vn2.size(); i++) // 获取叶子结点到根路径对应未访问结点数
{
node2 leaf = vn2[i];
int x = leaf.x, cnt = 0;
while (x != -1)
{
if (!vis[x])
{
cnt++;
vis[x] = 1;
}
else
{
break;
}
x = pre[x];
}
vn2[i].cnt = cnt;
}
printf("%d\n", K);
sort(vn2.begin(), vn2.end(), cmp); // 根据未访问节点数排序
for (int i = 0; i < vn2.size(); i++)
{
if (vn2[i].cnt)
{
printf("%d\n", vn2[i].x);
}
}
return 0;
}