旅行 基环树+dfs序

链接https://www.acwing.com/problem/content/536/

分析
n是5000,可以搞个 O ( n 2 ) O(n^2) O(n2)的做法。

要求字典序最小,可以先预处理一下,对每一层排个序,让每一层的节点被从小到大遍历。

n = m n =m n=m时,就是一棵树,题目中的字典序就是dfs序,直接每一层按从小到大搜索就可以。

n = m + 1 n=m+1 n=m+1时,这棵树中就形成了环,是一颗基环树。

在有环的时候搜就会重复,那就每次删除一条边,删除后再搜索当前树的dfs序,如果发现dfs序比已经保存的小,就更新,如果大了就直接剪枝掉。

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 5005;
#define INF 0x3f3f3f3f
struct edge
{
    
    
    int u,v;
    void add(int a,int b){
    
    
        u = a;
        v = b;
    }
}e[maxn];

vector<int> g[maxn];
int ans[maxn];
int vis [maxn];
int cnt = 1;
int flag;
int del_u,del_v;

int dfs(int u,int fa){
    
    
    if(!flag){
    
    
        if(u > ans[cnt])
            return 1;
        if(u < ans[cnt])
            flag = 1;
    }
    vis[u] = 1;
    ans[cnt++] = u;
    for(auto v: g[u]){
    
    
        if(vis[v])
            continue;
        if((u == del_u && v == del_v) || (u == del_v && v == del_u))
             continue;
        if(dfs(v,u)) return 1;
    }
    return 0;
}

int main()
{
    
    
    
    int n,m,u,v;
    cin>>n>>m;
    memset(ans,INF,sizeof(ans));
    for(int i = 0;i < m; i++ ){
    
    
        cin>>u>>v;
        e[i].add(u,v);
        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 - 1 ==m ){
    
    
        dfs(1,0);
        for(int i = 1;i <= n; i++)
            cout<<ans[i]<<" "; 
    }
    else{
    
    
        for(int i = 0;i < m; i++){
    
    
            memset(vis,0,sizeof(vis));
            del_u = e[i].u;
            del_v = e[i].v;
            flag = 0;
            cnt = 1;
            dfs(1,0);
        }
        for(int i = 1;i <= n; i++)
            cout<<ans[i]<<" ";
        
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/u011612364/article/details/115269866