HDU 4111 Alice and Bob 【DP解决博弈】
http://acm.hdu.edu.cn/showproblem.php?pid=4111
题目大意:详见http://acm.hrbust.edu.cn/index.php?m=ProblemSet&a=showProblem&problem_id=1719
解题思路:开始的时候一直在推规律。但是很苦x,比赛到最后都没推出来。
看了解题报告的状态转移方程才ac了此题。
最终的石子都会化成一堆。但是如果合并的话将奇偶性改变了一下,相当于缓了一步。
由于一堆石子只有一个很特殊。因此状态转移方程将他分开考虑。
dp[i][j]:表示i个1堆石子 ,将非一石子合并后的总数。dp[i][j]=1,表示Alice赢,否则输。因此有以下种状态转移而来:
拿走一个1的堆:dp[i-1][j]
合并2个1的堆:dp[i-2][j+3](当i>=2的时候) dp[i-2][2](j==0)
大堆拿一个:dp[i][j-1]
1的堆与大堆合并:dp[i-1][j+1];
代码如下:
View Code
#include<stdio.h> #include<string.h> int dp[55][50005]; int main() { int n, i, j, num1, sum, a, T, cas=0; memset(dp, 0, sizeof(dp)); for(i=0; i<=50001; i++) dp[0][i]=i%2; for(i=1; i<=52; i++) i%3==0?dp[i][0]=0:dp[i][0]=1; for(i=1; i<=52; i++) for(j=0; j<=50001; j++) { if(j==1) //大堆出现1 { dp[i][j]=dp[i+1][0]; continue; } if(dp[i-1][j]==0||(dp[i-1][j+1]==0&&j!=0)||(j!=0&&dp[i][j-1]==0)) //拿走小堆的一个 or 一个小堆与大堆合并 or 拿走大堆的一个 { dp[i][j]=1; continue; } if(i>=2) { if((j==0&&dp[i-2][2]==0)||(j>=1&&dp[i-2][j+3]==0)) //2个小堆对的合并 { dp[i][j]=1; continue; } } } scanf("%d", &T); while(T--) { scanf("%d", &n); num1=0, sum=0; for(i=0; i<n; i++) { scanf("%d", &a); if(a==1) num1++; else sum+=(a+1); } if(sum) sum--; cas++; printf("Case #%d: ", cas); if(dp[num1][sum]) printf("Alice\n"); else printf("Bob\n"); } return 0; }