洛谷 P5022 旅行(DFS+断环)

题目链接:https://www.luogu.com.cn/problem/P5022

首先对于m=n-1的情况非常好想:即这是一棵树,然后从1节点开始,搜一遍。注意要搜出来的序列的字典序最小,所以用邻接矩阵来存储,存的时候按当前节点能到的节点的编号从小到大排序。

当m=n的时候:这时候便是一个基环树,在树上的某一个地方会有一个环,会发现环上的有一条边是不会走的。然而并不确定这条边到底是哪一条,所以进行枚举断环。但找出环来太麻烦,所以可以直接枚举m条边中哪一条边不会走,每次看能否将n个点都走一遍,即cnt是否等于n。如果都能走,则每次更新字典序最小的ans。

关于将一条边断掉:不需要考虑复杂,只需要假设断掉的边的两个端点分别为x,y,在DFS时,如果当前的边的端点恰好是x,y,则直接continue即可。

AC代码:

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<vector>
 5 #include<algorithm>
 6 using namespace std;
 7 const int N=5010;
 8 vector<int> a[N];
 9 int cnt,tot,x,y,n,m;
10 struct node{
11     int to,from,next;
12 }edge[N<<1];
13 int head[N],k[N],ans[N],vis[N];
14 void add(int u,int v){
15     edge[tot].to=v;
16     edge[tot].from=u;
17     edge[tot].next=head[u];
18     head[u]=tot++;
19 }
20 void change(){
21     for(int i=1;i<=n;i++) ans[i]=k[i];
22 }
23 bool check(){
24     for(int i=1;i<=n;i++){
25         if(k[i]<ans[i]) return 1;
26         else if(k[i]>ans[i]) return 0;
27         else continue;
28     }
29 }
30 void work(int u,int fa){
31     if(vis[u]) return;
32     vis[u]=1;
33     ans[++cnt]=u;
34     for(int i=0;i<a[u].size();i++){
35         int v=a[u][i];
36         if(v==fa) continue;
37         work(v,u);
38     }
39 }
40 void DFS(int u,int fa){
41     if(vis[u]) return;
42     vis[u]=1;
43     k[++cnt]=u;
44     for(int i=0;i<a[u].size();i++){
45         int v=a[u][i];
46         if(v==fa) continue;
47         if((v==x&&u==y)||(v==y&&u==x)) continue;
48         DFS(v,u);
49     }
50 }
51 int main(){
52     memset(head,-1,sizeof(head));
53     scanf("%d%d",&n,&m);
54     for(int i=1;i<=m;i++){
55         int u,v;
56         scanf("%d%d",&u,&v);
57         a[u].push_back(v); a[v].push_back(u);
58         add(u,v); add(v,u);
59     }
60     for(int i=1;i<=n;i++) sort(a[i].begin(),a[i].end());
61     if(n==m){
62         for(int i=0;i<tot;i+=2){
63             cnt=0; x=edge[i].from; y=edge[i].to;
64             memset(vis,0,sizeof(vis));
65             DFS(1,-1);
66             if(cnt<n) continue;
67             if(ans[1]==0) change();
68             else if(check()) change();
69         }
70         for(int i=1;i<=n;i++) printf("%d ",ans[i]);
71         return 0;
72     }
73     work(1,-1);
74     for(int i=1;i<=n;i++) printf("%d ",ans[i]);
75     return 0;
76 }
AC代码
原文地址:https://www.cnblogs.com/New-ljx/p/13832694.html