题目描述
有一棵基环树 \(T\),你初始在一个点上。每次可以从下列选项中选择一项执行:
- 沿着一条边走到一个没有访问过的点;
- 沿着一条边返回一个访问过的点。
你需要依此法访问所有的 \(N\) 个点。每个点被首次访问的顺序形成了一个序列,求这个序列字典序最小的那个。
Solution
由数据规模知,这大概是一个时间复杂度 \(O(N^2)\) 的程序。
先考虑树的情况。
对于一个节点 \(k\),如果他有多个未访问儿子,那么每次走编号最小的那个永远是最优的。
所以我们建图的时候,先存下边,排序后再建图。这样就能保证我们找到的第一个答案就是最优答案。
for(int i=1;i<=m;++i){
sx=read();sy=read();
e[++len].x=sx;e[len].y=sy;
e[++len].x=sy;e[len].y=sx;
}
sort(e+1,e+len+1);
这样我们就能拿到 60 分,时间复杂度 \(O(M\log M+N)\)。
因为基环树删去环上一条边后退化成树,所以考虑枚举删除的边,然后转化成树的情况。时间复杂度 \(O(M\log M+N^2)\),期望得分 100。
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAXN=5010;
struct node{
int x,y,next;
node(){
x=y=next=0;
}
friend bool operator<(const node a,const node b){
if(a.x!=b.x) return a.x<b.x;
return a.y<b.y;
}
}e[MAXN+MAXN];
int len=0;
int n,m;
int sx,sy;
int first[MAXN];
int a[MAXN],H;
int ans[MAXN];
int fkx,fky;
int circle[MAXN];
int ST=0;
bool b[MAXN];
int bfind=0;
int fa[MAXN];
int findfa(int x){
if(fa[x]==x) return x;
return fa[x]=findfa(fa[x]);
}
void ins(int x,int y){
e[++len].x=x;e[len].y=y;
e[len].next=first[x];first[x]=len;
}
void dfs(int x,int fa,int h){
for(int i=first[x];i;i=e[i].next){
if(bfind) return;
int y=e[i].y;
if(fa==y) continue;
circle[h]=i;
if(b[y]){
bfind=h;
return;
}
b[x]=1;dfs(y,x,h+1);b[x]=0;
}
}
void work(int x,int fa){
a[H]=x;
for(int i=first[x];i;i=e[i].next){
int y=e[i].y;
if((x==fkx&&y==fky)||(x==fky&&y==fkx)) continue;
if(y==fa) continue;
++H;
work(y,x);
}
}
void update(){
for(int i=1;i<=n;++i){
if(ans[i]<a[i]) return;
if(a[i]<ans[i]) break;
}
for(int i=1;i<=n;++i)
ans[i]=a[i];
}
inline int read(){
int x=0; char c;
do c=getchar(); while(c<'0'||c>'9');
while(c>='0'&&c<='9')
x=x*10+c-48,c=getchar();
return x;
}
int main(){
n=read();m=read();
for(int i=1;i<=n;++i)
fa[i]=i;
for(int i=1;i<=m;++i){
sx=read();sy=read();
e[++len].x=sx;e[len].y=sy;
e[++len].x=sy;e[len].y=sx;
int x=findfa(sx),y=findfa(sy);
if(x!=y) fa[x]=y;
else ST=y;
}
sort(e+1,e+len+1);
memset(first,0,sizeof(first));
for(int i=len;i>=1;--i){
first[e[i].x]=i;
if(e[i].x==e[i+1].x) e[i].next=i+1;
}
memset(ans,63,sizeof(ans));
if(n==m){
memset(b,0,sizeof(b));b[ST]=1;
dfs(ST,0,1);
for(int i=1;i<=bfind;++i){
fkx=e[circle[i]].x;fky=e[circle[i]].y;
if(i==1&&fkx!=e[circle[bfind]].y) continue;
H=1;work(1,0);
if(H==n) update();
}
}else{
H=1;work(1,0);
update();
}
for(int i=1;i<=n;++i)
printf("%d ",ans[i]);
}