题解 P5022 【旅行】

· · 题解

一个DFS

这道题要求求出字典序最短的路径 如果一种情况一种情况地搜 肯定会T 所以我们这里用到一个贪心的思路 即 一个点 若连着若干个点 那么 先搜数字小的点 这样 只需要搜一遍 就可以保证得到的答案是字典序最小的

然后 这题需要分两种情况考虑 一种是 边数为n-1的情况 一种是边数为n 的情况(因为当边数为n时 会成环 当成环时 就可能会出现正解无法被搜索到的情况 如 有一个1-2-3-4连起来的环 DFS搜索的结果是1 2 4 3(因为DFS的特点就是要搜到底才会回溯)但是 答案是1 2 3 4 ) 但是 对于边数为n 的情况 我们可以把它转换为边数为n-1的情况 即 将n条边中的某一条删去 则此时总边数就会变为n-1 就可以快乐的DFS了 稍微需要注意的一点是 要判断一下删去这条边 会不会出现某个点没有边与他连接 不然就会T

下面是代码

#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
int n,m,ind=0;

vector <int> G[5001];

int a[5001][3];

int vis[5001];

int tp[5001];

int ans[5001];

void dfs(int s,int p,int q){
    if(vis[s]) return ;
    if(ind>n) return;
    vis[s]=1;
    tp[++ind]=s;
    if(ind==n){
        if(ans[1]==0){
            for(int i=1;i<=n;i++){
                ans[i]=tp[i];
            }
        }
        else{
            for(int i=1;i<=n;i++){
                if(ans[i]<tp[i]){
                    break;
                }
                else if(ans[i]>tp[i]){
                    for(int j=1;j<=n;j++){
                        ans[j]=tp[j];
                    }
                    break;
                }
            }
        }
    }
    for(int i=0;i<G[s].size();i++){
        if(s==p&&G[s][i]==q) continue;
        if(s==q&&G[s][i]==p) continue;//判断删边
        dfs(G[s][i],p,q);
    }
    vis[s]=0;//回溯清标记
}

int main(){
    cin>>n>>m;
    for(int i=1,u,v;i<=m;i++){
        cin>>u>>v;
        G[u].push_back(v);
        G[v].push_back(u);  
        a[i][1]=u;
        a[i][2]=v;
    }
    for(int i=1;i<=n;i++){
        sort(G[i].begin(),G[i].end());
    }
    for(int i=0,p,q;i<=m;i++){
        p=a[i][1];
        q=a[i][2];
        if(G[p].size()==1||G[q].size()==1) continue;//判断是否还会成一棵树
        ind=0;
        dfs(1,p,q);
        if(m==n-1) break;
    }
    for(int i=1;i<=n;i++){
        cout<<ans[i]<<" ";
    }
    return 0;
}