藍橋杯 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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM