hdu 4111 Alice and Bob 记忆化搜索 博弈论
Alice and Bob
Time Limit: 20 Sec Memory Limit: 256 MB
题目连接
http://acm.hdu.edu.cn/showproblem.php?pid=4111
Description
The rule of the new game is quite simple. At the beginning of the game, they write down N random positive integers, then they take turns (Alice first) to either:
1. Decrease a number by one.
2. Erase any two numbers and write down their sum.
Whenever a number is decreased to 0, it will be erased automatically. The game ends when all numbers are finally erased, and the one who cannot play in his(her) turn loses the game.
Here's the problem: Who will win the game if both use the best strategy? Find it out quickly, before they get bored of the game again!
Input
The first line contains an integer T(1 <= T <= 4000), indicating the number of test cases.
Each test case contains several lines.
The first line contains an integer N(1 <= N <= 50).
The next line contains N positive integers A1 ....AN(1 <= Ai <= 1000), represents the numbers they write down at the beginning of the game.
Output
For each test case in the input, print one line: "Case #X: Y", where X is the test case number (starting with 1) and Y is either "Alice" or "Bob".
Sample Input
Sample Output
Case #1: Alice Case #2: Bob Case #3: Bob
HINT
题意
给你n堆石头,你有两个选择,1.减少一堆石头数量1,2.合并两堆石头
如果遇到不能操作的情况就算输
题解:
这道题当成dp来做,dp[i][j]表示现在有i堆只有1个,j表示现在我能够操作次数
操作次数等于 sigma(a[i])-n+1,其中a[i]>1,n为满足条件的a[i]的个数
------------------------
那么转移方程就出来了,1个的,要么消去,要么和1个的合并,要么和多个的合并
然后就可以记忆化搜索搞了
代码:
//qscqesze #include <cstdio> #include <cmath> #include <cstring> #include <ctime> #include <iostream> #include <algorithm> #include <set> #include <vector> #include <sstream> #include <queue> #include <typeinfo> #include <fstream> #include <map> #include <stack> typedef long long ll; using namespace std; //freopen("D.in","r",stdin); //freopen("D.out","w",stdout); #define sspeed ios_base::sync_with_stdio(0);cin.tie(0) #define maxn 50051 #define mod 10007 #define eps 1e-9 int Num; char CH[20]; //const int inf=0x7fffffff; //нчоч╢С const int inf=0x3f3f3f3f; /* inline void P(int x) { Num=0;if(!x){putchar('0');puts("");return;} while(x>0)CH[++Num]=x%10,x/=10; while(Num)putchar(CH[Num--]+48); puts(""); } */ inline ll read() { ll x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } inline void P(int x) { Num=0;if(!x){putchar('0');puts("");return;} while(x>0)CH[++Num]=x%10,x/=10; while(Num)putchar(CH[Num--]+48); puts(""); } //************************************************************************************** int dp[100][maxn]; int a[maxn]; int dfs(int a,int b)//a 表示还有多少组为1 b表示还剩下多少次操作次数 { if(dp[a][b]!=-1) return dp[a][b]; dp[a][b]=0;//其他情况都是不可操作的 if(b==1) return dp[a][b]=dfs(a+1,0);//只剩一个单独的一,加入其它1中 if(a>=1&&!dfs(a-1,b))//直接去掉一个1 dp[a][b]=1; if(a>=1&&b&&!dfs(a-1,b+1))//将一个1合到其它数中 dp[a][b]=1; if(a>=2&&((b&&!dfs(a-2,b+3))||(b==0&&!dfs(a-2,2))))//将2个1并起来 dp[a][b]=1; if(b>=2&&!dfs(a,b-1))//减小一 dp[a][b]=1; return dp[a][b]; } int main() { //freopen("test.txt","r",stdin); memset(dp,-1,sizeof(dp)); int t=read(); for(int cas=1;cas<=t;cas++) { int flag=0; int sum=0; int n=read(); for(int i=0;i<n;i++) { a[i]=read(); if(a[i]==1) flag++; else sum+=a[i]+1; } sum--; dfs(flag,sum); if(dp[flag][sum]) printf("Case #%d: Alice\n",cas); else printf("Case #%d: Bob\n",cas); } }