某个国家有N个城市,编号0 至 N-1,他们之间用N - 1条道路连接,道路是双向行驶的,沿着道路你可以到达任何一个城市。你有一个旅行计划,这个计划是从编号K的城市出发,每天到达一个你没有去过的城市,并且旅途中经过的没有去过的城市尽可能的多(如果有2条路线,经过的没有去过的城市同样多,优先考虑编号最小的城市),直到所有城市都观光过一遍。现在给出城市之间的交通图T,以及出发地点K,你来设计一个旅行计划,满足上面的条件。例如:
(K = 2)
![](http://img.51nod.com/upfile/000fbd22/08d194a9c7e74afb0000000000000004.png)
第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
这是来自tls的回答:
考虑将树根设为K,观察到以下结论:
1. 每次必然会走到叶子,否则可以继续向下走到叶子,使得访问的点增多。
2. 考虑每次访问到的未访问的点,一定是与叶子相连的、在叶子到点K路径上的一条连续的链,所以问题可以转化为:令每个叶子分别支配一条链,使得标号小的点尽量支配多的点,最后根据支配的点数多少、标号大小依次访问。
所以做法可以是树上贪心,从深到浅依次确定每个点被其子树里哪个叶子支配,然后使得那个点的支配点个数加一,最后用基数排序排出支配点数降序、标号大小升序即可。
就是先找出所有叶子结点,按照深度排序,深度大的在前,然后对这些叶子向上访问,并进行标记,对每个叶子记录访问的节点数,最后再按访问的结点数排序就行了。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
using namespace std;
#define rep(i,a,n) for (int i=a;i<n;i++)
#define per(i,a,n) for (int i=n-1;i>=a;i--)
#define pb push_back
#define mp make_pair
#define fi first
#define se second
typedef vector<int> VI;
typedef long long ll;
typedef pair<int,int> PII;
const ll mod=1000000007;
const int MAXN=50000*2;
struct node
{
int to,next;
}edge[MAXN*2];
int tol=0;
int head[MAXN],deep[MAXN];
void add(int u,int v)
{
edge[++tol].to=v,edge[tol].next=head[u],head[u]=tol;
}
struct fun
{
int x,d,cnt;
fun(int u,int v,int f=0):x(u),d(v),cnt(f) {}
bool operator < (const fun& b)const{
return d>b.d||(d==b.d&&x<b.x);
}
};
vector<fun> st;
int pa[MAXN];
void dfs(int x,int fa)
{
pa[x]=fa;
bool flag=false;
for(int i=head[x];i;i=edge[i].next)
{
int v=edge[i].to;
if(v==fa) continue;
else flag=true;
deep[v]=deep[x]+1;
dfs(v,x);
}
if(!flag) st.pb(fun(x,deep[x]));
}
bool cmp(fun a,fun b)
{
return a.cnt>b.cnt||(a.cnt==b.cnt&&a.x<b.x);
}
bool vis[MAXN];
int main()
{
int n,k;
scanf("%d%d",&n,&k);
rep(i,1,n)
{
int v;
scanf("%d",&v);
add(v,i),add(i,v);
}
deep[k]=1;
vis[k]=true;
dfs(k,-1);
sort(st.begin(),st.end());
for(int i=0;i<st.size();i++)
{
fun t=st[i];
int x=t.x,cnt=0;
while(x!=-1)
{
if(!vis[x]) cnt++,vis[x]=true;
else break;
x=pa[x];
}
st[i].cnt=cnt;
}
printf("%d\n",k);
sort(st.begin(),st.end(),cmp);
for(int i=0;i<st.size();i++)
if(st[i].cnt) printf("%d\n",st[i].x);
return 0;
}