您的位置:首页 > 其它

POJ 3688 Cheat in the Game (博弈 dp)

2016-09-04 16:17 507 查看

题意:

有俩人玩一个取石子的游戏,你是裁判。游戏中有W块石头和N张卡片,卡片上分别写着数字ai。玩家随机抽走一张卡片,按卡片上的数字从石头堆中取走相应数量的石头,如果石头不够,玩家重新抽卡片,取走最后一块石头的玩家获胜;如果石头堆为空仍然未分出胜负,则拿回所有石头和卡片重新开始。

现在先手玩家贿赂了你,请你帮他构造必胜条件。游戏中的卡片是固定的,但W可供你操作。问有多少小于或等于M的W满足要求。

思路:

1:如果W 只能 表示成特定的n张卡片上的数字之和,那么:

当n为偶数时,{先手一张,后手一张}循环n/2次拿完石头,后手玩家必胜。

当n为奇数时,{先手一张,后手一张}循环n/2 + 1次拿完石头,先手玩家必胜。(我们需要的条件)

2:如果W既可以表示成奇数张卡片数字之和,也可以表示成偶数张卡片数字之和,那么结果不确定。

3:如果W既无法表示成奇数张卡片数字之和,也无法表示成偶数张卡片数字之和,则W无法用卡片取完,就会一直玩下去。。。

dp[i][1] 表示 i可以由奇数张卡片组成。

dp[i][0] 表示i可以由偶数张卡片组成。

AC代码:

#include <iostream>
#include <string.h>
#include <cstdio>
#include <algorithm>

using namespace std;

int a[10010];
bool dp[100000][2];

int main()
{
int n;
int m;
while(scanf("%d%d",&n,&m),n){
memset(dp,false,sizeof(dp));
for(int i = 1;i <= n ;i++){
scanf("%d",a+i);
}
int ans = 0;
for(int i = 1;i <= n;i++){
//dp[a[i]][1] = true; 这行不能放在这里,因为这样的话就相当于这个卡片取了两次。
for(int j = m; j > a[i]; j--){
if(dp[j-a[i]][1])
dp[j][0] = true;
if(dp[j-a[i]][0])
dp[j][1] = true;
}
dp[a[i]][1] = true;
}
for(int i = 1;i <= m;i++){
if(dp[i][1] != 0 && dp[i][0] == 0 ) // 只能被奇数张卡片组成。
ans++;
}
printf("%d\n",ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: