[NOIp2018] luogu P5022 旅行

题目描述

有一棵基环树 \(T\),你初始在一个点上。每次可以从下列选项中选择一项执行:

  1. 沿着一条边走到一个没有访问过的点;
  2. 沿着一条边返回一个访问过的点。

你需要依此法访问所有的 \(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]);
}

猜你喜欢

转载自www.cnblogs.com/yhmaster/p/11725121.html