感觉这个题没什么好说的。
对于树的情况直接从1开始搜(保证字典序最小),从大到小排序它的子节点,再接着搜。
对于基环树,直接(n^2)暴力删边即可,用(vector)存边,排序预处理,枚举边,给边两侧的点打上标记,在搜到他们俩时直接continue就行,剩下的和树一样
#include<queue>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<iostream>
#include<vector>
using namespace std;
typedef long long ll;
const int maxm=10007;
int n,m;
int pre[maxm],last[5007],other[maxm],l,nxt[maxm];
bool vis[5007];
vector<int >e[5007];
int duanx,duany;
int ans[5007],cnt,q[5007];
void add(int x,int y)
{
l++;
pre[l]=last[x];
last[x]=l;
other[l]=y;
nxt[l]=x;
}
void dfs(int x)
{
int pl[5007];//开在里面,避免下次直接覆盖
vis[x]=1;
printf("%d ",x);
int cnt=0;
for(int p=last[x];p;p=pre[p])
{
int v=other[p];
if(vis[v]) continue;
pl[++cnt]=v;
}
if(cnt==0) return;
sort(pl+1,pl+cnt+1);
for(int i=1;i<=cnt;i++)
if(!vis[pl[i]])dfs(pl[i]);
}
inline void lcx_change()
{
for(register int i=1;i<=n;i++)
ans[i]=q[i];
}
inline bool check()
{
for(register int i=1;i<=n;i++)
{
if(q[i]==ans[i]) continue;
else if(q[i]>ans[i]) return 0;
else return 1;
}
}
void wtz_AK(int x)
{
vis[x]=1;
q[++cnt]=x;
for(int i=0;i<e[x].size();i++)
{
int v=e[x][i];
if(vis[v]||(duanx==x&&duany==v)||(duanx==v&&duany==x)) continue;
wtz_AK(v);
}
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
{
int x,y;
scanf("%d%d",&x,&y);
add(x,y);
add(y,x);
e[x].push_back(y);
e[y].push_back(x);
}
if(m==n-1)dfs(1);
else
{
for(int i=1;i<=n;i++)
sort(e[i].begin(),e[i].end());
for(register int i=1;i<=l;i+=2)
{
cnt=0;
duanx=nxt[i];
duany=other[i];
wtz_AK(1);
memset(vis,0,sizeof(vis));
if(cnt!=n) continue;
if(ans[1]==0)
lcx_change();
else if(check()) lcx_change();
}
for(int i=1;i<=n;i++)
printf("%d ",ans[i]);
}
return 0;
}
感觉要多使stl啊