题目描述
给定n个城市,m条双向道路的图, 不存在两条连接同一对城市的道路,也不存在一条连接一个城市和它本身的道路。并且, 从任意一个城市出发,通过这些道路都可以到达任意一个其他城市。小 Y 只能通过这些道路从一个城市前往另一个城市。
小 Y 的旅行方案是这样的:任意选定一个城市作为起点,然后从起点开始,每次可 以选择一条与当前城市相连的道路,走向一个没有去过的城市,或者沿着第一次访问该 城市时经过的道路后退到上一个城市。当小 Y 回到起点时,她可以选择结束这次旅行或 继续旅行。需要注意的是,小 Y 要求在旅行方案中,每个城市都被访问到。(注意:同一条道路不能走两遍,也就是回头路只能走一次)
为了让自己的旅行更有意义,小 Y 决定在每到达一个新的城市(包括起点)时,将 它的编号记录下来。她知道这样会形成一个长度为 nn 的序列。她希望这个序列的字典序 最小,你能帮帮她吗? 对于两个长度均为 n 的序列 A和 B,当且仅当存在一个正整数 x,满足以下条件时, 我们说序列 A 的字典序小于 B。
对于任意正整数 1≤i<x,序列A的第 i 个元素 Ai 和序列 B 的第 i 个元素 Bi 相同。
序列 A 的第 x 个元素的值小于序列 B 的第 x 个元素的值。
题目大意
给你一个图,让你找到字典序最小的访问顺序。
解法
因为图近似一棵树,对于前15组数据,是一棵树,我们就只需要每次按照当前节点子节点从小到大的顺序来排列就可以了。(这个东西应该是贪心)
那么对于接下来的几组数据,因为多了一条边,那么就一定会形成环,我们就每一次拆掉一条边,做和前面的做法一样的就可以了。
AC代码
#include<bits/stdc++.h>
#define ms(a,b) memset(a,b,sizeof(a))
#define pb push_back
#define N 5005
#pragma GCC optimize(2)
using namespace std;
struct edge{
int u,to;
}E[N<<1];
vector<int>G[N];
int ans[N],H[N];
int n,m,tot,cnt,sign1,sign2;
bool vis[N];
int read(){
int w=0,x=0;char ch=0;
while(!isdigit(ch))w|=ch=='-',ch=getchar();
while(isdigit(ch))x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
return w?-x:x;
}
void dfs(int u,int fa){
if(vis[u])return;
vis[u]=1;
ans[++tot]=u;
for(int i=0;i<(int)G[u].size();i++){
int v=G[u][i];
if(v==fa||(v==sign1&&u==sign2)||(v==sign2&&u==sign1)) continue;
dfs(v,u);
}
}
bool judge(int *a,int *b){
for(int i=1;i<=n;i++) {
if(a[i]==b[i]) continue;
else return a[i]<b[i];
}
return true;
}
int main(){
n=read(),m=read();
for(int i=1;i<=m;i++){
int u=read(),v=read();
G[u].pb(v);
G[v].pb(u);
E[++cnt]=(edge){u,v};
E[++cnt]=(edge){v,u};
}
for(int i=1;i<=n;i++) sort(G[i].begin(),G[i].end());
if(m==n-1){
ms(vis,0);
tot=0;
dfs(1,-1);
for(int i=1;i<=n;i++) printf("%d ",ans[i]);
}
else{
for(int i=1;i<=cnt;i+=2){
sign1=E[i].u,sign2=E[i].to;
ms(vis,0); tot=0; int res[N]; for(int j=1;j<=n;j++) res[j]=ans[j];
dfs(1,-1);
if(tot==n){
if(res[1]==0) continue;
if(judge(res,ans)) for(int j=1;j<=n;j++) ans[j]=res[j];
}
else for(int j=1;j<=n;j++) ans[j]=res[j];
}
for(int i=1;i<=n;i++) printf("%d ",ans[i]);
}
return 0;
}