• 蓝桥杯 2014本科C++ B组 李白打酒 三种实现方法 枚举/递归


    标题:李白打酒

     

        话说大诗人李白,一生好饮。幸好他从不开车。

     

        一天,他提着酒壶,从家里出来,酒壶中有酒2斗。他边走边唱:

     

        无事街上走,提壶去打酒。

        逢店加一倍,遇花喝一斗。

     

        这一路上,他一共遇到店5次,遇到花10次,已知最后一次遇到的是花,他正好把酒喝光了。

     

        请你计算李白遇到店和花的次序,可以把遇店记为a,遇花记为b。则:babaabbabbabbbb 就是合理的次序。像这样的答案一共有多少呢?请你计算出所有可能方案的个数(包含题目给出的)。

     

    注意:通过浏览器提交答案。答案是个整数。不要书写任何多余的内容。

    答案:14

    先提供两种用枚举方式来解决此问题的方法,前面14个格子要摆放的是0,1(用0标识花,1标识店)

    方案一,用0,1把前14个格子按照字典序打印出来,但要保证其0,1的总数小于规定总数。然后模拟这个过程。

    代码:

     1 /*方法1*/#include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #define MAXN 20
     5 using namespace std;
     6 int num[MAXN],s=0;//花记为 0,店记为 1 
     7 void dfs(int cur)
     8 {
     9     int n0=0,n1=0,i,j,c=2;
    10     bool flag=true;
    11     if(cur==15)
    12     {
    13         for(i=1;i<=14;i++)
    14         {
    15             c=num[i]==0?c-1:c*2;
    16             if(c==0)
    17             {
    18                 flag=false;
    19                 break;
    20             }
    21         }
    22         if(flag==false)
    23             return ;
    24         else
    25         {
    26             if(c==1)
    27             {
    28                 s++;
    29                 for(i=1;i<=14;i++)
    30                     cout<<num[i]<<' ';
    31                 cout<<0<<endl;
    32             }
    33             return ;
    34         }
    35     }
    36     for(i=0;i<=1;i++)
    37     {
    38         if(i==0)
    39         {
    40             for(j=1;j<=cur-1;j++)
    41             {
    42                 if(num[j]==0)
    43                     n0++;
    44             }
    45             if(n0<9)
    46             {
    47                 num[cur]=0;
    48                 dfs(cur+1);
    49                 num[cur]=-1;
    50             }    
    51         }
    52         else
    53         {
    54             for(j=1;j<=cur-1;j++)
    55             {
    56                 if(num[j]==1)
    57                     n1++;
    58             }
    59             if(n1<5)
    60             {
    61             num[cur]=1;
    62             dfs(cur+1);
    63             num[cur]=-1;
    64             }
    65             
    66         }
    67     }
    68 } 
    69 int main()
    70 {
    71     memset(num,-1,sizeof(num));
    72     dfs(1);
    73     cout<<s<<endl;
    74     return 0;
    75 }
    View Code

    方案二,我们其实只要将5个1填入前14个格子里,其实是 种方案,我们依旧可以用枚举的方式实现,依次去按字典序排列5个数(但必须是按递增的序列排列)选取的数字是从1-14里选择

    代码:

     1 /*方法2*/ 
     2 #include<iostream>
     3 #include<cstdio>
     4 #include<cstring>
     5 #define MAXN 20
     6 using namespace std;
     7 int num[MAXN],ans[MAXN],s=0;//花记为 0,店记为 1 
     8 void dfs(int cur,int k)
     9 {
    10     int ok,c=2,i,j;
    11     bool flag=true;
    12     if(cur==6)
    13     {
    14         memset(num,0,sizeof(num));
    15         for(i=1;i<=5;i++)
    16         {
    17             num[ans[i]]=1;
    18         }
    19         for(i=1;i<=14;i++)
    20         {
    21             c=num[i]==0?c-1:c*2;
    22             if(c==0)
    23             {
    24                 flag=false;
    25                 break;
    26             }
    27         }
    28         if(flag==false)
    29             return ;
    30         else
    31         {
    32             if(c==1)
    33             {
    34                 s++;
    35                 for(i=1;i<=14;i++)
    36                     cout<<num[i]<<' ';
    37                 cout<<0<<endl;
    38             }
    39             return ;
    40         }
    41     }
    42     for(i=k+1;i<=14;i++)
    43     {
    44         ok=1;
    45         for(j=1;j<=cur-1;j++)
    46         {
    47             if(ans[j]==i)
    48                 ok=0;
    49         }
    50         if(ok)
    51         {
    52             ans[cur]=i;
    53             dfs(cur+1,i);        
    54         }    
    55     }
    56 }
    57 int main()
    58 {
    59     memset(ans,0,sizeof(ans));
    60     dfs(1,0);
    61     cout<<s<<endl;
    62     return 0;
    63 }
    View Code

    而递归的方式实现将变得更加简洁。

    由于实现此过程的总数等于开头为a和开头为b的总和,再递归这两个决策,直到a==0&&b==0&&c==1结束。

    代码:

     1 /*递归*/
     2 #include<iostream>
     3 using namespace std;
     4 int sum=0;
     5 int f(int a,int b,int c){  // a:店的总数 b:花的总数减1 c:酒的初值
     6 // 任何初始状况,都有两个可能:先遇到店,或者先遇到花
     7    if(a>0)
     8      f(a-1,b,c*2); // 逢店加一倍
     9    if(b>0)
    10      f(a,b-1,c-1); // 遇花喝一斗
    11    if(a==0&&b==0&&c==1) //这个是满足要求的终止条件。没有店剩下,还剩一朵花和一斗酒
    12      sum=sum+1;
    13     return sum;
    14 }
    15 int main()
    16 {
    17     f(5,9,2);
    18     cout<<sum<<endl;
    19     return 0;
    20 }
    View Code
  • 相关阅读:
    第一篇日志
    Spring mvc 4系列教程(三)—— Spring4.X的新特性
    Spring mvc 4系列教程(二)——依赖管理(Dependency Management)和命名规范(Naming Conventions)
    Spring mvc 4系列教程(一)
    【管理心得之三十六】《黄帝内经》中的一句话
    【管理心得之三十五】好习惯也能惹“骂名”
    【管理心得之三十四】“禅宗境界”的员工
    【管理心得之三十三】管理者的“眉头”
    【管理心得之三十二】PMP杂谈---------爱情必胜术
    【管理心得之三十一】我的位置
  • 原文地址:https://www.cnblogs.com/fancy-itlife/p/4299846.html
Copyright © 2020-2023  润新知