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; }
相关文章推荐
- 【POJ 3688 Cheat in the Game】+ dp + 巴什博弈
- POJ 3688 Cheat in the Game(作弊博弈)
- POJ 3688 Cheat in the Game
- POJ 3688 Cheat in the Game 已翻译
- POJ 3688 Cheat in the Game(博弈论)
- 携程第二场 Poj 1182 食物链(带权并查集) Poj 1948 Triangular Pastures Poj(dp二维背包) 1740 A New Stone Game(博弈)
- POJ 1678 I Love this Game!(博弈DP)
- poj 1678 I Love this Game!(博弈dp)
- POJ 2631 Roads in the North(求树的直径,两次遍历 or 树DP)
- POJ 2631 Roads in the North(树形dp)
- POJ 1678 I Love this Game!(博弈DP)
- poj 1678 I Love this Game!(博弈dp)
- Poj 2996 Help Me with the Game
- poj 2388 Who's in the Middle
- POJ 2996 Help Me with the Game
- poj1289 The Cat in the Hat
- poj1027——The Same Game
- POJ 2084 Game of Connection DP
- POJ 2388 Who's in the Middle 排序
- zoj 1074 || poj 1050 To the Max(简单DP)