hdu4111 Alice and Bob 【转载】

转载请注明出处,谢谢 http://blog.csdn.net/ACM_cxlove?viewmode=contents           by---cxlove

可惜没有机会去现场做,不过当时肯定是不会。

题意:有N堆石头,可以把两堆合成一堆,也可以把一堆去掉一个。

由于总数不变,最终总是要一个个拿完。那么有机会获胜的一方,肯定是先要把所有的合在一起,那么最终就拼奇偶数了。所以双方都要合并。总共就是sigma(ai)+n-1。

而且如果没有某堆只有一个的话,对方是阻挡不住的,没有取完,便被合并了。

所以就要考虑某堆只有一个的情况,单独考虑。

其中的操作包括:

把某堆只有一个的,取走

把两堆只有一个的,合并

把某堆只有一个的,合并给不是一个的

把不是一个的,取走一个

采用记忆化搜索

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<cmath>
 5 #include<algorithm>
 6 #define N 10005
 7 #define LL long long
 8 #define inf 1<<29
 9 #define eps 1e-7
10 using namespace std;
11 int sg[55][60005];
12 int get_sg(int i,int j){
13     if(sg[i][j]!=-1)
14         return sg[i][j];
15     if(j==1)
16         return sg[i][j]=get_sg(i+1,0);
17     sg[i][j]=0;
18     //某堆只有一个的取掉
19     if(i>=1&&!get_sg(i-1,j))
20         sg[i][j]=1;
21     //把不是1个的取走一个
22     else if(j>=1&&!get_sg(i,j-1))
23         sg[i][j]=1;
24     //把1个的合并给不是1个的
25     else if(i>=1&&j>0&&!get_sg(i-1,j+1))
26         sg[i][j]=1;
27     //把两个1个的合并,其中注意,合并是需要一步的
28     else if(i>=2&&((j==0&&!get_sg(i-2,j+2))||(j&&!get_sg(i-2,j+3))))
29         sg[i][j]=1;
30     return sg[i][j];
31 }
32 int main(){
33     int n,t,cas=0,k;
34     scanf("%d",&t);
35     memset(sg,-1,sizeof(sg));
36     while(t--){
37         scanf("%d",&n);
38         int one=0,sum=0;
39         while(n--){
40             scanf("%d",&k);
41             if(k==1)
42                 one++;
43             else
44                 sum+=(k+1);
45         }
46         if(sum)
47             sum--;
48         printf("Case #%d: ",++cas);
49         if(get_sg(one,sum))
50              puts("Alice");
51         else
52              puts("Bob");
53     }
54     return 0;
55 }
原文地址:https://www.cnblogs.com/symons1992/p/2992220.html