51nod 1273 旅行计划——思维题

某个国家有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————————————————————————————————————————————————————以下搬自51nod题解考虑将树根设为K,观察到以下结论:1. 每次必然会走到叶子,否则可以继续向下走到叶子,使得访问的点增多。2. 考虑每次访问到的未访问的点,一定是与叶子相连的、在叶子到点K路径上的一条连续的链,所以问题可以转化为:令每个叶子分别支配一条链,使得标号小的点尽量支配多的点,最后根据支配的点数多少、标号大小依次访问。以做法可以是树上贪心,从深到浅依次确定每个点被其子树里哪个叶子支配,然后使得那个点的支配点个数加一,最后用基数排序排出支配点数降序、标号大小升序即可。当然我懒 所以写的是sort代替基排

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int M=50007;
int read(){
    int ans=0,f=1,c=getchar();
    while(c<‘0‘||c>‘9‘){if(c==‘-‘) f=-1; c=getchar();}
    while(c>=‘0‘&&c<=‘9‘){ans=ans*10+(c-‘0‘); c=getchar();}
    return ans*f;
}
char s[23];int len;
inline void outx(int x)
{
    if(!x){putchar(‘0‘);return;}
    while(x)s[++len]=x%10,x/=10;
    while(len)putchar(s[len--]+48);
}
int T,n,rt;
int first[M],cnt;
struct node{int to,next;}e[M*2];
void ins(int a,int b){e[++cnt]=(node){b,first[a]}; first[a]=cnt;}
void insert(int a,int b){ins(a,b); ins(b,a);}
int sum;
struct pos{int d,pos;}p[M];
bool cmp(pos a,pos b){return a.d!=b.d?a.d>b.d:a.pos<b.pos;}
void dfs(int x,int fa,int deep){
    bool f=true;
    for(int i=first[x];i;i=e[i].next){
        int now=e[i].to;
        if(now!=fa) f=false,dfs(now,x,deep+1);
    }
    if(f&&x!=rt) p[++sum].pos=x,p[sum].d=deep;
}
int vis[M];
struct Ans{int h,pos;}q[M];
bool qcmp(Ans a,Ans b){return a.h!=b.h?a.h>b.h:a.pos<b.pos;}
int find(int x,int fa){
    if(vis[x]||x==rt) return 1;
    for(int i=first[x];i;i=e[i].next){
        int now=e[i].to;
        if(now==fa) continue;
        if(find(now,x)) return T++,vis[x]=1,1;
    }
    return 0;
}
int main()
{
    int x;
    n=read(); rt=read();
    for(int i=1;i<n;i++) x=read(),insert(i,x);
    for(int i=1;i<=n;i++) p[i].pos=i;
    dfs(rt,-1,0); sort(p+1,p+1+sum,cmp);
    for(int i=1;i<=sum;i++){
        q[i].pos=p[i].pos;
        T=0; find(p[i].pos,-1);
        q[i].h=T;
    }
    sort(q+1,q+1+sum,qcmp);
    printf("%d\n",rt); for(int i=1;i<=sum;i++) printf("%d\n",q[i].pos);
    return 0;
}


 
时间: 2024-08-02 11:05:34

51nod 1273 旅行计划——思维题的相关文章

【luogu1137】旅行计划 [拓扑排序]

P1137 旅行计划 最长路 DAG 拓扑排序的过程中直接 DP 算是从头开始图论的学习....emmmmmmm 通常情况下,在实现的时候会维护一个队列以及每个结点的入度.在删 除边的时候顺便把相应结点的入度减去,当这个结点入度为 0 的时候直接 将其加入队列. 大概对图论形成了惯性思维 看到就怕QAQ 1 #include<iostream> 2 #include<cstdio> 3 #include<queue> 4 #include<cstring>

cogs 2. 旅行计划 dijkstra+打印路径小技巧

2. 旅行计划 ★★   输入文件:djs.in   输出文件:djs.out   简单对比时间限制:3 s   内存限制:128 MB [题目描述] 过暑假了,阿杜准备出行旅游,他已经查到了某些城市的两两之间的距离及可行路线(可行路线有方向),如下图所示.请你编程计算从阿杜所住城市到其它城市的最短路径以帮助阿杜制定旅行计划. [输入格式] 输入由若干行组成,第一行有三个整数 n(1≤n≤100) 为城市数,m(1≤m≤n2) 为城市间道路数,s(0≤s≤n−1) 是阿杜所住城市.第 2 至 m

Unique Encryption Keys (思维题 预处理)

题目 题意:给m个数字, q次询问, 询问b到e之间如果有重复数字就输出, 没有就输出OK 思路:用f[i]数组 记录从i开始向后最近的有重复数字的 位置, 如 1 3 2 2, 则f[1] = 4; 如果离a最近的重复数字的位置 都大于b, 就说明没有重复数字. f[]数组需要预处理,从后向前. 1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <vector>

sdut 2847 Monitor (思维题)

题目 题意:给定a, b, x, y;  求使c, d; 使c:d = x :y; 且c<=a, d<=b, 而且c, d尽量大. 先求最小倍数, 再用最小倍数乘 x, y; 1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <cmath> 5 using namespace std; 6 7 long long gcd(long long a, l

hdu 4972 A simple dynamic programming problem (转化 乱搞 思维题) 2014多校10

题目链接 题意:给定一个数组记录两队之间分差,只记分差,不记谁高谁低,问最终有多少种比分的可能性 分析: 类似cf的题目,比赛的时候都没想出来,简直笨到极点..... 1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <cstdlib> 5 #include <cmath> 6 #include <vector> 7 #include &

学习方法_2011年编写和锻炼的思维题

1.多看,多练,多想,多总结,最重要就是不停的写代码! 给自己的目标:一天代码量最少800行,无论是什么代码,如果练习的量不够,就重复做已经写过的代码. 思维题: 找出这当中数字 1,11,31,4113,612314 的规律是怎样的? 1,11,表示前面的数有1个131,表示前面所有的数有3个14113,表示前面的所有的数有4个1.1个3以此类推,前面所有的数有6个1.2个3.1个4,即为612314 1.两个无窗的房间,其中一间有三个电灯,另一间里面有三个开关,三个开关各控制三个电灯.问:每

思维题 URAL 1718 Rejudge

题目传送门 1 /* 2 题意:数据加10组,再删掉第6组数据,问rejudge后最少最多几个作者收到邮件 3 思维题:当错在6时结果是不一定,错在7时是一定改变,因为会变成6 4 思路没错,但用结构题排序一直WA,代码有毒!学习使用set容器. 5 */ 6 #include <cstdio> 7 #include <algorithm> 8 #include <cstring> 9 #include <cmath> 10 #include <str

ZOJ 3829 贪心 思维题

http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3829 现场做这道题的时候,感觉是思维题,自己智商不够,不敢搞,想着队友智商好,他们搞吧,但是没出来这题...... 以后任何时候,都自信点....该想的还是好好自己想,这类题感觉就是先去找性质,然后一点点找规律,如果必要的话,自己提出一点猜想,然后如果自己举不出来反例,就暂时认为是正确的 下午搞了一下午,发现还是悲剧,晚上参考了两个题解 http://blog.csdn.

欧拉计划21-23题

21.Amicable numbers Let d(n) be defined as the sum of proper divisors of n (numbers less than n which divide evenly into n). If d(a) = b and d(b) = a, where a  b, then a and b are an amicable pair and each of a and b are called amicable numbers. For