题意 : 有 n 个球队,给出主客场胜负图,找出一个序列 1、2、3..... 使得 1 战胜过 2 、2 战胜过 3、3 战胜过 4..... n 战胜过 1 ( 这个序列是 1~n 的其中一个全排列 )
分析 : n 最大就只有 20 ,明摆着让你搜,但是这题我失了志啊,下面说几个搜索要注意的点
① 因为能构成环,所以答案序列肯定是从 1 开始
② 搜索时候如果接下来没有一个点是能够战胜 1 的那么则不继续搜 ( 没有这个剪枝会被第四个点卡住 )
③ 题目给出的图是不对称的,而且要注意到 A - B == 'W' 等价为 B-A == 'L' !!!
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#include<bits/stdc++.h> using namespace std; const int maxn = 25; char G[maxn][maxn]; bool vis[maxn]; int n, ans[maxn]; set<int> s; int Can; bool DFS(int x, int num) { if(num == n){ if(G[ans[n-1]][ans[0]] == 'W' || G[ans[0]][ans[n-1]] == 'L'){ for(int i=0; i<n; i++){ printf("%d", ans[i]); if(i!=n-1) putchar(' '); }puts(""); return true; }else return false; }else{ int cnt = 0; for(int i=0; i<num; i++) if(s.count(ans[i])) cnt++; if(cnt >= Can) return false; ///剩下球队都不能战胜 1 ,说明肯定没有解 } for(int i=1; i<=n; i++){ if((G[x][i] == 'W'|| G[i][x] == 'L') && !vis[i]){ ans[num] = i; vis[i] = true; if(DFS(i, num+1)) return true; vis[i] = false; } } return false; } int main(void) { scanf("%d", &n); for(int i=1; i<=n; i++) for(int j=1; j<=n; j++) scanf(" %c", &G[i][j]); for(int i=2; i<=n; i++) if(G[1][i]=='L' || G[i][1]=='W') s.insert(i); ///记录能战胜 1 的球队的编号 Can = (int)s.size(); memset(vis, false, sizeof(vis)); vis[1] = true; ans[0] = 1; if(!DFS(1, 1)) puts("No Solution"); return 0; }