旅行
题目描述
简化题意:从起点1开始遍历完所有点,使字典序最小,求该字典序(每条边至多经过两次,进入一次,回溯一次)
解析
首先考虑是一棵树的情况,显然只需要将每个点连出的边按从大到小拍一遍序,因此dfs时一定会先走编号小的城市,因此排完序过后,直接输出dfs序即可
接着再来考虑基环树的情况,暴力删边!!!,因为尽管是一棵基环树,但是最后遍历过后,遍历的路径仍然是一棵树,即有一条边一定不会遍历到,因此枚举删掉的边,然后按照第一种情况瞎搞就好了。
至于加强版的数据,就应该在环上枚举断边,再操作
代码
#include<bits/stdc++.h>
#include<iostream>
#define M 5009
using namespace std;
const int ff=1e5+1;
const int inf=1e9+1;
int nxt[M*2],tot,to[M*2],w[M*2],first[M],n,m,cnt,b[M],ans[M];
bool vis[M],bj[M][M],bjj;
int st[ff],ed[ff];
int read(){
int f=1,re=0;
char ch;
for(ch=getchar();!isdigit(ch)&&ch!='-';ch=getchar());
if(ch=='-'){
f=-1;
ch=getchar();
}
for(;isdigit(ch);ch=getchar())
re=(re<<3)+(re<<1)+ch-'0';
return re*f;
}
void add1(int x,int y){
nxt[++tot]=first[x];
first[x]=tot;
to[tot]=y;
}
void dfs1(int r)
{
printf("%d ",r);
for(int i=first[r];i;i=nxt[i])
{
int u=to[i];
if(vis[u]) continue;
vis[u]=1;
dfs1(u);
}
}
int zhan[ff],top;
int ban[5001][5001];
int check()
{
if(top<n)
return 0;
for(int i=1;i<=n;++i)
{
if(zhan[i]<ans[i])
return 1;
if(zhan[i]>ans[i])
return 0;
}
}
void copy()
{
for(int i=1;i<=n;++i)
ans[i]=zhan[i];
}
int tag[ff];
void dfs2(int r,int las)
{
zhan[++top]=r;tag[r]=1;
for(int i=first[r];i;i=nxt[i])
{
int u=to[i];
if(u==las) continue;
if(ban[r][u]||ban[u][r]||tag[u])
continue;
vis[u]=1;
dfs2(u,r);
}
}
int main(){
n=read(),m=read();
if(m==n-1){
int x,y;
for(int i=1;i<=m;i++){
x=read(),y=read();
bj[x][y]=1;
bj[y][x]=1;
}
for(int i=1;i<=n;i++)
for(int j=n;j>=1;j--)
if(bj[i][j]) add1(i,j);
vis[1]=1;
dfs1(1);
return 0;
}
else
{
for(int i=1;i<=m;i++)
{
int x,y;
x=read(),y=read();
st[i]=x;ed[i]=y;
bj[x][y]=1;
bj[y][x]=1;
}
for(int i=1;i<=n;i++)
for(int j=n;j>=1;j--)
if(bj[i][j]) add1(i,j);
for(int i=1;i<=n;++i)
ans[i]=inf;
for(int i=1;i<=m;++i)
{
memset(tag,0,sizeof(tag));
top=0;
ban[st[i-1]][ed[i-1]]=ban[ed[i-1]][st[i-1]]=0;
ban[st[i]][ed[i]]=ban[ed[i]][st[i]]=1;
dfs2(1,0);
if(check()) copy();
}
for(int i=1;i<=n;++i)
cout<<ans[i]<<" ";
}
}