【搜索-剪枝-偏难】PAT-天梯赛-L3-015. 球队“食物链”

L3-015. 球队“食物链”

某国的足球联赛中有N支参赛球队,编号从1至N。联赛采用主客场双循环赛制,参赛球队两两之间在双方主场各赛一场。

联赛战罢,结果已经尘埃落定。此时,联赛主席突发奇想,希望从中找出一条包含所有球队的“食物链”,来说明联赛的精彩程度。“食物链”为一个1至N的排列{ T1 T2 ... TN },满足:球队T1战胜球队T2,球队T2战胜球队T3,……,球队T(N-1)战胜球队TN,球队TN战胜球队T1【像是构成了一个遍历了所有节点一次的回路或者可以形成了一个环;那么如果存在,起点1一定可以做开头!毕竟可以形成一个环!】

现在主席请你从联赛结果中找出“食物链”。若存在多条“食物链”,请找出字典序最小的。【按照DFS进行有序搜索,一定满足字典序!】

注:排列{ a1 a2 ...aN }在字典序上小于排列{ b1 b2 ... bN },当且仅当存在整数K(1 <= K <= N),满足:aK < bK且对于任意小于K的正整数i,ai=bi【等价于字典序的解释吧】

输入格式:

输入第一行给出一个整数N(2 <= N <= 20),为参赛球队数。随后N行,每行N个字符,给出了NxN的联赛结果表,其中第i行第j列的字符为球队i在主场对阵球队j的比赛结果:“W”表示球队i战胜球队j,“L”表示球队i负于球队j,“D”表示两队打平,“-”表示无效(当i=j时)。输入中无多余空格。

【这里需要再注意一点,mp[i][j]=='L' 等价于 mp[j][i]='W' ,这两个语句等可以表达出 i  战胜过j ;第二次WA的时候仔细揣摩了上面的那几个“过”字,有所新的领悟了!

AC题解如下:

基础搜索即可,保证有序:

1、第一次剪枝加了句,if(ans==1)return ;   //此处剪枝,多获得三分

2、第二次剪枝,把图转化成了邻接矩阵!//然并卵

3、第三次剪枝,在每次向下进行迭代的时候,跑一遍for循环——如果没有一个点可以回连到起点1就return ,就是下面未标记的解集里没有可以再回去连接到出发点1的路径了!

(写的时候省了点事,从下标0到n-1进行遍历,正好符合字符串的存贮位置!!)


  1 #include<iostream>
  2 #include<stdio.h>
  3 #include<string.h>
  4 #include<math.h>
  5 #include<algorithm>
  6 #include<queue>
  7 #include<set>
  8 #include<vector>
  9 #include<string>
 10 #include<stack>//16:06--
 11 #define  inf 0x3f3f3f3f
 12 #define  dinf 0x7fffffff*1.0
 13 using namespace std;   //L3-015. 球队“食物链”
 14 #define N 1200
 15 #define ll long long
 16 int n;
 17 char mp[22][22];
 18 int ans;
 19 int tmp[22];//存贮结果的数组
 20 int vis[22];//标记行
 21 vector<int>G[22];//然并卵的邻接矩阵
 22 void dfs(int k,int step){//k表示要搜索的下一行的标号,step表示已经完成的行数
 23   //  printf("k=%d step=%d
",k,step);
 24     if(ans==1)return ;   //此处剪枝,多获得三分
 25     tmp[step]=k+1;
 26     if(step==n-1){
 27         if(mp[k][0]=='W'){
 28             ans=1;
 29         }
 30         return ;
 31     }
 32     int i;
 33     for( i=0;i<n;i++){
 34         if(!vis[i]&&(mp[i][0]=='W'))
 35             break;
 36     }
 37     if(i==n)return ;//存在未收录的点不与1相连,就是下面未确认的解集里没有可以连接到出发点0的路径了
 38 
 39     for( i=0;i<G[k].size();i++){
 40         int v=G[k][i];//取出k战胜过的队伍编号
 41         if(!vis[v]){
 42             vis[v]=1;
 43             dfs(v,step+1);
 44             vis[v]=0;
 45         }
 46     }
 47 }
 48 void get_graph(){//生成邻接矩阵
 49     for(int i=0;i<n;i++){
 50         for(int j=0;j<n;j++){
 51             if(mp[i][j]=='W'){
 52                 G[i].push_back(j);
 53             }
 54         }
 55     }
 56 }
 57 int main(){
 58 
 59     while(~scanf("%d",&n)){
 60         for(int i=0;i<=20;i++)//初始化邻接矩阵
 61             G[i].clear();
 62         for(int i=0;i<n;i++){
 63             scanf("%s",mp[i]);
 64         }
 65         for(int i=0;i<n;i++){
 66             for(int j=0;j<n;j++){   //mp[i][j]=='L' 等价于 mp[j][i]='W'
 67                 if(mp[i][j]=='L'){
 68                     if(mp[j][i]=='L')
 69                         mp[i][j]='W';
 70                     mp[j][i]='W';
 71                 }
 72             }
 73         }
 74         get_graph();//存成邻接矩阵
 75         ans=0;
 76         tmp[0]=1;
 77         for(int i=0;i<n;i++){
 78             memset(vis,0,sizeof(vis));
 79             vis[0]=1;
 80             if(mp[0][i]=='W'){
 81                 vis[i]=1;
 82                 dfs(i,1);
 83             }
 84             if(ans==1)break;
 85         }
 86         if(ans==1){
 87             for(int i=0;i<n-1;i++)
 88                 printf("%d ",tmp[i]);
 89             printf("%d
",tmp[n-1]);
 90         }else{
 91             printf("No Solution
");
 92         }
 93     }
 94 
 95     return 0;
 96 }
 97 
 98 /*
 99 3
100 -LL
101 L-L
102 LL-
103 */
View Code(带详细的注释)
原文地址:https://www.cnblogs.com/zhazhaacmer/p/8619070.html