NOIP 2018旅行题解

从佳木斯回来刷一刷去年没A的题

 

题目描述

小 Y 是一个爱好旅行的 OIer。她来到 X 国,打算将各个城市都玩一遍。

小Y了解到, X国的 nn 个城市之间有 mm 条双向道路。每条双向道路连接两个城市。 不存在两条连接同一对城市的道路,也不存在一条连接一个城市和它本身的道路。并且, 从任意一个城市出发,通过这些道路都可以到达任意一个其他城市。小 Y 只能通过这些 道路从一个城市前往另一个城市。

小 Y 的旅行方案是这样的:任意选定一个城市作为起点,然后从起点开始,每次可 以选择一条与当前城市相连的道路,走向一个没有去过的城市,或者沿着第一次访问该 城市时经过的道路后退到上一个城市。当小 Y 回到起点时,她可以选择结束这次旅行或 继续旅行。需要注意的是,小 Y 要求在旅行方案中,每个城市都被访问到。

为了让自己的旅行更有意义,小 Y 决定在每到达一个新的城市(包括起点)时,将 它的编号记录下来。她知道这样会形成一个长度为 nn 的序列。她希望这个序列的字典序 最小,你能帮帮她吗? 对于两个长度均为 nn 的序列 AA 和 BB,当且仅当存在一个正整数 xx,满足以下条件时, 我们说序列 AA 的字典序小于 BB。

  • 对于任意正整数 1 ≤ i < x1i<x,序列 AA 的第 ii 个元素 A_iAi 和序列 BB 的第 ii 个元素 B_iBi 相同。
  • 序列 AA 的第 xx 个元素的值小于序列 BB 的第 xx 个元素的值。

输入格式

输入文件共 m + 1m+1 行。第一行包含两个整数 n,m(m ≤ n)n,m(mn),中间用一个空格分隔。

接下来 m 行,每行包含两个整数 u,v (1 ≤ u,v ≤ n)u,v(1u,vn) ,表示编号为 uu 和 vv 的城市之 间有一条道路,两个整数之间用一个空格分隔。

输出格式

输出文件包含一行,nn 个整数,表示字典序最小的序列。相邻两个整数之间用一个 空格分隔。

输入输出样例

输入 #1
6 5 
1 3 
2 3 
2 5 
3 4 
4 6
输出 #1
1 3 2 5 4 6
输入 #2
6 6 
1 3 
2 3 
2 5 
3 4 
4 5 
4 6
输出 #2
1 3 2 4 5 6

说明/提示

【数据规模与约定】

对于 100\%100% 的数据和所有样例, 1 \le n \le 50001n5000 且 m = n − 1 或 m = nm=n 。

对于不同的测试点, 我们约定数据的规模如下:

 

 

 

 

看看数据范围,n和m的关系,有60分是m=n-1的,说明这是一颗树,而另外40分m=n,说明这是一颗基环树,就是一颗带环的树

 

60分非常容易就可以得到,贪心一下,然后直接在树上跑dfs就好了 ,(去年的我啥也不会连这60也没得)

 

我们考虑100分的做法,他不是一颗基环树吗,和普通树相比,无非就是多了一个环,数据范围5000,考虑O(n*n*logn)可过,显然可以直接枚举删每一条边,然后记录最优解(字典序最小的)

 

这题我本想用tarjan做,可是实力不允许啊...

 

好吧是tarjan写挂了

 

这道题还可以加剪枝,判环,每次看这条边是不是在环上,不过针对这道题的数据来讲不用这么做。

 

23333前向星存图大法好,不过贪心按边排序的时候就需要费点劲了,不如vector

 

我绝对不会抛弃信仰去用vector(其实是不会)

 

直接上代码吧,机房某奆老说我的代码是老太太的裹脚布,又臭又长,但是我觉得可读性还是比较高的吧

 

  1 #pragma GCC optimize(2)
  2 #pragma GCC optimize(3)
  3 #include <bits/stdc++.h>
  4 #define MAXN 20050
  5 using namespace std;
  6 int head[MAXN>>2],top,n,k,point,ans[MAXN];
  7 int cnt,low[MAXN],m,dfn[MAXN],qwq,sta[MAXN],sum,an[MAXN],qaq;
  8 int circle[MAXN];
  9 int a[MAXN],b[MAXN],visss[MAXN];
 10 int x[MAXN],y[MAXN];
 11 int lx,ly;
 12 bool viss[MAXN],ju;
 13 struct Node{
 14     int to,nxt;
 15 }g[MAXN>>1];
 16 inline void add(int u,int v)
 17 {
 18     g[++top].to=v;
 19     g[top].nxt=head[u];
 20     head[u]=top;
 21 }
 22 inline void dfs(int u,int fa)
 23 {
 24     ans[++point]=u;
 25     int cnt=0;
 26     int vis[1000];
 27     memset(vis,0,sizeof(vis));
 28     for(register int i=head[u];i;i=g[i].nxt)
 29     {
 30         int v=g[i].to;
 31         if(v==fa)
 32         continue;
 33         vis[++cnt]=v;    
 34         //dfs(v,u);
 35     }
 36     sort(vis+1,vis+1+cnt);
 37     for(register int i=1;i<=cnt;i++)
 38     {
 39         dfs(vis[i],u);
 40     }
 41 } 
 42 inline void solve(int x)
 43 {
 44     int k=0;
 45     for(register int i=head[x];i;i=g[i].nxt)
 46     {
 47         int v=g[i].to;
 48         a[++k]=v;
 49     }
 50     sort(a+1,a+1+k);
 51     int j=1;
 52     for(register int i=head[x];i;i=g[i].nxt)
 53     {
 54         g[i].to=a[j];
 55         j++;
 56     }
 57 }
 58 inline void dfs2(int u,int fa)
 59 {
 60     b[++cnt]=u;
 61     viss[u]=1;
 62     for(register int i=head[u];i;i=g[i].nxt)
 63     {
 64         int v=g[i].to;
 65         if(v==fa||viss[v])
 66         continue;
 67         if((u==lx&&v==ly)||(v==lx&&u==ly))
 68         continue;
 69         dfs2(v,u);
 70     }
 71 
 72 }
 73 bool check()
 74 {
 75     for(int i=1;i<=n;i++)
 76     {
 77         if(b[i]<ans[i])
 78         return 1;
 79         if(b[i]>ans[i])
 80         return 0;
 81     }
 82     return 0;
 83 }
 84 int main()
 85 {
 86     cin>>n>>m;
 87     for(register int i=1;i<=m;i++)
 88     {
 89         scanf("%d%d",&x[i],&y[i]);
 90         add(x[i],y[i]);
 91         add(y[i],x[i]);
 92     }
 93     if(m==n-1)
 94     {
 95         dfs(1,-1);
 96         for(int i=1;i<=point;i++)
 97         cout<<ans[i]<<" ";
 98         cout<<endl;
 99         return 0;
100     }
101     else
102     {
103         for(register int i=1;i<=n;i++)
104         solve(i);
105         for(register int i=1;i<=n;i++)
106         {
107             ans[i]=n;
108         }
109         for(register int i=1;i<=m;i++)
110         {
111             lx=x[i];
112             ly=y[i];
113             cnt=0;
114             memset(viss,0,sizeof(viss));
115             dfs2(1,0);
116             if(cnt<n)
117             continue;
118             if(check())
119             {
120                 for(int j=1;j<=n;j++)
121                 ans[j]=b[j];
122             }
123         }
124         for(register int i=1;i<=n;i++)
125         printf("%d ",ans[i]);
126     }
127 } 
View Code

 

 

posted @ 2019-08-07 16:55  落筱  阅读(401)  评论(2编辑  收藏  举报