题目链接: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 }