Luogu P5022 travel (base ring tree + ring breaking method)

Original question link
meaning:
a tree, starting from 1, record the number every time a new point is reached. Find a way to make the recorded number lexicographical order the smallest.
Idea: It
is said in the question that m<=n, which means that this tree may be a base ring tree.
If this tree is an ordinary tree, dfs it after sorting it directly, and the point with the smallest lexicographical order is taken each time. If this tree is a base ring tree, we must first clarify a property. There must be an edge on the ring that does not pass. You can simulate the process manually. So we can enumerate the edge that does not pass each time, and take the smallest lexicographic order after finding the answer. If this side does not pass, it will have no effect on the answer and the correctness can be ensured.
The complexity is about n*n, and it can be passed by inhaling oxygen.
Code:

const int maxn=2e5+100;
int h[maxn],idx;
struct node{
    
    
    int u,v,ne;
}edge[maxn*2];
int n,m;
vector<int>g[maxn];

void add(int u,int v){
    
    
    edge[idx]={
    
    u,v,h[u]};h[u]=idx++;
}

int timetmp=0;
int res[maxn],tmp[maxn],vis[maxn];

void dfs(int u,int fa,int delu,int delv,int tmp[]){
    
    
    if(vis[u]) return ;
    vis[u]=1;
    tmp[++timetmp]=u;
    for(int i=0;i<g[u].size();i++){
    
    
        int t=g[u][i];
        if(t==fa) continue;
        if(t==delu&&u==delv) continue;///当前边是本次删除的边
        if(t==delv&&u==delu) continue;
        dfs(t,u,delu,delv,tmp);
    }
}

bool check(){
    
    
    for(int i=1;i<=n;i++)
        if(res[i]<tmp[i]) return 0;
        else if(res[i]>tmp[i]) return 1;//需要更改
}

int main(){
    
    
    memset(h,-1,sizeof h);
    n=read(),m=read();
    for(int i=1;i<=m;i++){
    
    
        int u=read(),v=read();
        add(u,v);add(v,u);
        g[u].push_back(v);
        g[v].push_back(u);
    }
    for(int i=1;i<=n;i++) sort(g[i].begin(),g[i].end());///对每个点的出边进行排序
    if(n==m){
    
    ///基环树
        for(int i=0;i<idx;i+=2){
    
    ///枚举删哪条边
            timetmp=0;
            memset(vis,0,sizeof vis);
            dfs(1,-1,edge[i].u,edge[i].v,tmp);
            if(timetmp<n) continue;///走不到所有的点
            if(res[1]==0||check()){
    
    
                for(int j=1;j<=n;j++) res[j]=tmp[j];///未被更新或是当前走法的字典序更小
            }
        }
    }
    else dfs(1,-1,-1,-1,res);
    for(int i=1;i<=n;i++) printf("%d ",res[i]);
	return 0;
}

reference:

Guess you like

Origin blog.csdn.net/weixin_45675097/article/details/110305309
Recommended