[博弈dp] hdu 4778 Gems Fight

给出g种颜色的宝石,然后有B个背包,S代表到时候每种颜色的宝石凑齐S个能变成一个魔法石
然后B行数输入,每个包里有哪些宝石
然后A,B轮流拿包,每个包只能拿一次,拿出包把宝石放地上。
如果能变成魔法石则拿走魔法石,下一次还这个人拿包,没变成则换人。
魔法石的个数就是获得分数,问两人最优的时候分差是多少。
思路:
只有21个包,状压dp。
然后发现不管顺序如何 最后构成的魔法石的个数是一定的。
然后在不同的二进制状态下,所剩在地面上的宝石是一定的。
那么就可以dp[i] 代表i这个状态下 先手取所获得的最多得分。
dp[(1<<B)-1] 则是先手的答案了
然后已知构成魔法石数sum
则答案就是  dp[(1<<B)-1]-(sum-dp[(1<<B)-1])
每次只要枚举取拿个包 然后保留最大值

代码:

[cpp] view plaincopy

    1. #include"cstdlib"
    2. #include"cstdio"
    3. #include"cstring"
    4. #include"cmath"
    5. #include"queue"
    6. #include"algorithm"
    7. #include"iostream"
    8. #define inf 99999999
    9. using namespace std;
    10. int bag[22][12],c[12];
    11. int dp[1<<22];
    12. int g,n,s;
    13. int dfs(int x,int sum,int used[])
    14. {
    15. if(x==0||sum==0) return 0;
    16. if(dp[x]!=inf) return dp[x];
    17. int ans=0,mark[12];
    18. memset(mark,0,sizeof(mark));
    19. for(int i=0; i<n; i++)
    20. {
    21. int pp=0;
    22. if(x&(1<<i))
    23. {
    24. int tep=x^(1<<i),cnt=0;
    25. for(int j=0; j<g; j++)
    26. {
    27. mark[j]=used[j]+bag[i][j];
    28. cnt+=mark[j]/s;
    29. mark[j]%=s;
    30. }
    31. if(cnt>0) pp=cnt+dfs(tep,sum-cnt,mark);  //构成魔法石继续取
    32. else pp=sum-dfs(tep,sum,mark);         //换人了  得到的就是别人剩下的
    33. ans=max(ans,pp);
    34. }
    35. }
    36. return dp[x]=ans;
    37. }
    38. int main()
    39. {
    40. while(scanf("%d%d%d",&g,&n,&s),(g+n+s))
    41. {
    42. memset(bag,0,sizeof(bag));
    43. memset(c,0,sizeof(c));
    44. for(int i=0; i<n; i++)
    45. {
    46. int x;
    47. scanf("%d",&x);
    48. while(x--)
    49. {
    50. int y;
    51. scanf("%d",&y);
    52. bag[i][y-1]++;
    53. c[y-1]++;
    54. }
    55. }
    56. int sum=0;
    57. for(int i=0; i<g; i++) sum+=c[i]/s;  //统计能构成多少个魔法石
    58. for(int i=0; i<(1<<n); i++) dp[i]=inf;
    59. int used[12];
    60. memset(used,0,sizeof(used));
    61. int ans=dfs((1<<n)-1,sum,used);
    62. printf("%d\n",ans-(sum-ans));
    63. }
    64. return 0;
    65. }
时间: 2024-10-09 20:04:46

[博弈dp] hdu 4778 Gems Fight的相关文章

HDU 4778 Gems Fight!(dp)

HDU 4778 Gems Fight! 题目链接 题意:有n个背包,包里有一些宝石,现在爱丽丝和你轮流选背包,把包里宝石丢到锅中,然后如果锅中有宝石数量到s个,就会得到魔法石,并且可以继续选背包,两人都按最优策略去取,问最后两人魔法石会差多少. 思路:dp,dp[s]表示选背包状态为s时候的值,然后去记忆化搜索即可,注意如果当前生成魔法石就继续加,否则就减即可 代码: #include <stdio.h> #include <string.h> #include <algo

hdu 4778 Gems Fight! 状压dp

转自wdd :http://blog.csdn.net/u010535824/article/details/38540835 题目链接:hdu 4778 状压DP 用DP[i]表示从i状态选到结束得到的最大值 代码也来自wdd 1 /****************************************************** 2 * File Name: b.cpp 3 * Author: kojimai 4 * Creater Time:2014年08月13日 星期三 11时

(状压dp)HDU 4778 Gems Fight!

Gems Fight! Time Limit: 20000/10000 MS (Java/Others)    Memory Limit: 327680/327680 K (Java/Others)Total Submission(s): 2395    Accepted Submission(s): 1087 Problem Description Alice and Bob are playing "Gems Fight!": There are Gems of G differe

hdu 4778 Gems Fight!(状态压缩+博弈+记忆化)

Gems Fight! Time Limit: 20000/10000 MS (Java/Others)    Memory Limit: 327680/327680 K (Java/Others) Total Submission(s): 1383    Accepted Submission(s): 587 Problem Description Alice and Bob are playing "Gems Fight!": There are Gems of G differe

hdu 4778 Gems Fight!(状态压缩DP)

又是一道状态压缩,刚开始老是往博弈的方法想,总是没思路. #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int N=21; const int inf=0x3f3f3f3f; int g,n,s; int sum[1<<N]; int res[10]; int c[22][10]; i

hdu 4778 Gems Fight!

第一次写状压dp-- 题意:http://blog.csdn.net/dyx404514/article/details/15506601 状压dp+博弈吧-- #include<iostream> #include<map> #include<string> #include<cstring> #include<cstdio> #include<cstdlib> #include<cmath> #include<q

hdu 4778 Rabbit Kingdom(状态压缩)

题目链接:hdu 4778 Rabbit Kingdom 题目大意:Alice和Bob玩游戏,有一个炉子,可以将S个相同颜色的宝石换成一个魔法石,现在有B个包,每个包里有若干个宝石,给出宝石的颜色.现在由Alice开始,两人轮流选取一个包的宝石放入炉中,每当获得一个魔法石时,可以额外获得一次机会再选一个包放入.两人均按照自己的最优策略,问说最后Alice的魔法石-Bob的魔法石是多少. 解题思路:状态压缩,221,对于每次移动到下一个状态,如果获得的魔法石g非零,则说明下一个状态还是自己在取,则

简单的dp hdu 数塔(水题)

数塔 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 21314    Accepted Submission(s): 12808 Problem Description 在讲述DP算法的时候,一个经典的例子就是数塔问题,它是这样描述的: 有如下所示的数塔,要求从顶层走到底层,若每一步只能走到相邻的结点,则经过的结点的数字之和最大是多少

UVA 1558 - Number Game(博弈dp)

UVA 1558 - Number Game 题目链接 题意:20之内的数字,每次可以选一个数字,然后它的倍数,还有其他已选数的倍数组合的数都不能再选,谁先不能选数谁就输了,问赢的方法 思路:利用dp记忆化去求解,要输出方案就枚举第一步即可,状态转移过程中,选中一个数字,相应的变化写成一个函数,然后就是普通的博弈问题了,必胜态之后必有必败态,必败态之后全是必胜态 代码: #include <stdio.h> #include <string.h> const int N = 105