• 【搜索-剪枝-偏难】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(带详细的注释)
  • 相关阅读:
    win7下如何配置ODBC数据源
    串口小票打印机调试命令
    如何测试一个网页登陆界面
    Cookie是否是httponly
    XSS攻击 (安全方面)和传统防御技术
    Linux下查看文件和文件夹大小
    linux停止和查看启动服务的命令使用方法
    查看Linux下系统资源占用常用命令(top、free、uptime)
    三种经典iPhone上网络抓包方法详解
    如何用Fiddler对Android应用进行抓包
  • 原文地址:https://www.cnblogs.com/zhazhaacmer/p/8619070.html
Copyright © 2020-2023  润新知