问题 D: 小k的硬币问题

Posted dwvictor

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了问题 D: 小k的硬币问题相关的知识,希望对你有一定的参考价值。

问题 D: 小k的硬币问题

时间限制: 1 Sec  内存限制: 128 MB
提交: 21  解决: 5
[提交] [状态] [命题人:jsu_admin]

题目描述

小k和小p一起玩一个游戏,有n堆硬币,每人轮流拿硬币,每次可以拿走1~5枚硬币,(必须拿完前一堆硬币才能开始拿后面一堆硬币,如果当前这堆硬币只剩下一枚,那么此次机会只能拿一枚),谁拿走的硬币多则获胜,两个人都足够聪明,后拿的人有一次机会能够一次拿走当前这堆硬币,请问比赛的结果是什么。

输入

第一行包含一个整数 T,表示有 T组测试数据。
接下来依次描述 T 组测试数据。对于每组测试数据:
第一行为两个整数 n,k,表示有n堆硬币,k为1则表示小k先拿,k为0则表示小k后拿。
接下来一行,有n个整数m1.....mn,表示每堆硬币的数量。 

0<T<10,0<n<=1000,0<m<=10

输出

如果小k能赢则输出1,平手则输出0,否则输出-1.

样例输入 Copy

4
1 1
10
5 0
9 9 3 5 6
6 0
1 1 1 1 1 1
2 1
10 1

样例输出 Copy

0
1
0
1


这道题要用到博弈论的思维来解答,先来分析每一堆硬币,数量为 1~10,当数量为 1 是,没法选择策略,只能拿 1 个,当数量为 2~5 时先选的人可以选择拿走 n-1 个,下 一堆硬币有优先选择权,也可以选择拿走 n 个,下一堆硬币后选,当数量为 6 时,只 有一种策略,就是拿走 5 个(因为拿走 5 个以下时,另一个人就能决定你下一堆硬币 的先后手,题目已经申明两个人都足够聪明),这是下一堆硬币先选,当数量为 7~10 的时候,可以选择拿走 n-6 个,此时对方只能拿走 5 个,然后自己拿走剩下的 1 个,


下一堆硬币后选,也可以直接拿走   5  个,让对方决定自己下堆硬币是先手还是后手。

因为考虑到一开始后手的人有一次一次性拿走一堆硬币的机会,所以以该角色进行倒 推(倒推的话,每个人在选择的时候都能看出自己之后怎么选才是最合适的),分为

4 个状态,该堆硬币有优先选择权,且有一次机会已经用过,2.该堆硬币没有优先选择 权,且一次机会已经用过,3.该堆硬币有优先选择权,且有一次机会,4.该堆硬币没有 优先选择权,且没有机会,保存每种状态下能拿到的最多的硬币数量。从后往前开始 逆推时,要考虑的如果有一次机会的话,可以通过这一次机会来改变自己下一堆硬币 的先后手,且如果是后手,对方只会选择让你拿到最少硬币的策略。当逆推结束是, 第二种状态能拿到的最多的硬币数量就是,后手这个角色能拿到的最多的硬币数量。

 

 我的暴搜tle

技术分享图片
  1 #include<stdio.h>
  2 #include<string.h>
  3 int a[1010];
  4 int b[2];
  5 int m,n;
  6 int sum = -1;
  7 //a,b
  8 //a = 0,c = 1; 
  9 void dfs(int i,int c,int d,int temp){
 10 //    printf("%d ",c);
 11 //    printf("%d ",d);
 12 //    printf("%d ",a[i]);
 13 //printf("%d ",temp);
 14     if(i==m+1)
 15     {
 16         if(n==0){
 17         
 18         if(c<d){
 19     //    printf("%d %d",c,d);
 20         sum = 1;
 21     //    i--;
 22         return ;
 23     }
 24     else if(sum!=1&&c == d)
 25     {
 26         sum = 0;
 27     //    i-- ;
 28         return ;
 29     }
 30 //    i--;
 31     return ;
 32     }
 33     else
 34     {
 35             if(c>d){
 36     //    printf("%d %d",c,d);
 37         sum = 1;
 38     //    i--;
 39         return ;
 40     }
 41     else if(sum!=1&&c == d)
 42     {
 43         sum = 0;
 44     //    i-- ;
 45         return ;
 46     }
 47 //    i--;
 48     return ;
 49     }
 50     
 51 }
 52     
 53     if(a[i]==1)
 54     {
 55         //temp 0  dy  c dy !k 
 56         if(temp == 0){
 57         
 58         dfs(++i,c++,d,1-temp),i--,c--,1-temp;
 59         return; 
 60     }
 61         else{
 62         
 63         dfs(++i,c,d++,1-temp),i--,c,d--,1-temp;
 64         return; 
 65     }
 66             //d[n]++,n = 1-n;
 67     }
 68         
 69             else if(2<=a[i]&&a[i]<=5){
 70                 //1
 71             //    d[n]+=a[i]-1,d[1-n] +=1;
 72             if(temp==0) //a+=a[i] - 1 d += 1{
 73             {
 74             
 75                 dfs(++i,c+=a[i] - 1, d += 1,temp),i--,c-=a[i] - 1, d -= 1;
 76                 //2
 77                 dfs(++i,c+=a[i],d,1-temp),i--,c-=a[i],d,1-temp;
 78             //    d[n]+=a[i],n = 1-n;
 79             return; 
 80                     }
 81                     else{
 82                         dfs(++i,d+=a[i] - 1, c += 1,temp),i--,d-=a[i] - 1, c -= 1;
 83                 //2
 84                 dfs(++i,d+=a[i],c,1-temp),i--,d-=a[i],c,1-temp;
 85                 return; 
 86                     }
 87             }
 88             else if(a[i]==6){
 89 //                d[n] += 5;
 90 //                d[1-n]++;
 91             if(temp == 0){
 92                     dfs(++i,c+=5,d++,temp),i--,c-=5,d--;
 93                     return; 
 94             }
 95             else{
 96             
 97             dfs(++i,d+=5,c++,temp),i--,d-=5,c--;
 98         //    i--
 99         return; 
100     }
101             }
102             else if(a[i]>=7&&a[i]<=10){
103                 //1
104                 if(temp ==0){
105                 
106                     dfs(++i,c+=a[i]-6+1,d+=5,1-temp),i--,c-=a[i]-6+1,d-=5,1-temp;
107                 //d[n] += a[i] - 6,d[1-n] += 5,d[n]+=1,n = 1-n;
108                 //2
109             //    i--;
110                     dfs(++i,c+=5,d+=a[i]-5,temp),i--,c-=5,d-=a[i]-5;
111             //        i--;
112                 //d[n] += 5;
113                 //2.1
114             //    d[1-n] +=a[i] - 5;
115                 dfs(++i,c+=6,d+=a[i]-6,1-temp),i--,c-=6,d-=a[i]-6,1-temp;
116             //    i--;
117             return; 
118             }
119             else    if(temp ==1){
120                 
121                     dfs(++i,d+=a[i]-6+1,c+=5,1-temp),i--,d-=a[i]-6+1,c-=5,1-temp;
122             //        i--;
123                 //    printf("%d",d);
124                 //d[n] += a[i] - 6,d[1-n] += 5,d[n]+=1,n = 1-n;
125                 //2
126                     dfs(++i,d+=5,c+=a[i]-5,temp),i--,d-=5,c-=a[i]-5;
127                 //    i--;
128                 //d[n] += 5;
129                 //2.1
130             //    d[1-n] +=a[i] - 5;
131             if(m!=1)
132                 dfs(++i,d+=6,c+=a[i]-6,1-temp),i--,d-=6,c-=a[i]-6,1-temp;
133                 //dfs(++i,d+=6,c+=a[i]-6,1-temp),i--,d-=6,c-=a[i]-6,1-temp;
134             //    i--;
135             return; 
136             }
137                 //2.2
138             //    d[1-n] +=a[i] - 5 -1,d[n]++,n = 1-n;
139             }
140             
141 }
142 int main(){
143     int t;
144     
145     
146     scanf("%d",&t);
147     while(t--){
148         //分别为堆数 
149         memset(a,0,sizeof(a));
150         sum = -1;
151         scanf("%d%d",&m,&n);
152         for(int i = 1;i<=m;i++){
153             scanf("%d",&a[i]);
154         }
155         int temp = n;
156         dfs(1,0,0,temp);
157 //        for(int i = 1;i<=m;i++){
158 //            if(a[i]==1)
159 //            d[n]++,n = 1-n;
160 //            else if(2<=a[i]&&a[i]<=5){
161 //                //1
162 //                b[n]+=a[i]-1,b[1-n] +=1;
163 //                //2
164 //                b[n]+=a[i],n = 1-n;
165 //                        
166 //            }
167 //            else if(a[i]==6){
168 //                b[n] += 5;
169 //                b[1-n]++;
170 //                
171 //            }
172 //            else if(a[i]>=7&&a[i]<=10){
173 //                //1
174 //                b[n] += a[i] - 6,b[1-n] += 5,b[n]+=1,n = 1-n;
175 //                //2
176 //                b[n] += 5;
177 //                //2.1
178 //                b[1-n] +=a[i] - 5;
179 //                //2.2
180 //                b[1-n] +=a[i] - 5 -1,b[n]++,n = 1-n;
181 //            }
182 //            
183 //        }
184         if(sum){
185             printf("1
");
186         }
187         else if(sum==0)
188         {
189             printf("0
");
190         }
191         else if(sum ==-1)
192         {
193             printf("-1
");
194         }
195     }
196 }
View Code

 













以上是关于问题 D: 小k的硬币问题的主要内容,如果未能解决你的问题,请参考以下文章

抛硬币问题

春招好题 | 动态规划——硬币问题及其变形

LeetCode 2218. 从栈中取出 K 个硬币的最大面值和

codeforces 160A-C语言解题报告

动态规划算法:硬币的最大总和(小于或等于k)

LeetCode排列硬币