(状压dp)HDU 4778 Gems Fight!

本文介绍了一个名为GemsFight!的游戏策略分析问题。玩家通过收集宝石并转化为魔法石来获胜。文章详细阐述了使用动态规划算法解决该问题的过程,并提供了一段完整的C++实现代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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 different colors , packed in B bags. Each bag has several Gems. G different colors are numbered from color 1 to color G.
  Alice and Bob take turns to pick one bag and collect all the Gems inside. A bag cannot be picked twice. The Gems collected are stored in a shared cooker.
  After a player ,we name it as X, put Gems into the cooker, if there are S Gems which are the same color in the cooker, they will be melted into one Magic Stone. This reaction will go on and more than one Magic Stone may be produced, until no S Gems of the same color remained in that cooker. Then X owns those new Magic Stones. When X gets one or more new Magic Stones, he/she will also get a bonus turn. If X gets Magic Stone in a bonus turn, he will get another bonus turn. In short,a player may get multiple bonus turns continuously.
  There will be B turns in total. The goal of "Gems Fight!" is to get as more Magic Stones than the opponent as possible.
  Now Alice gets the first turn, and she wants to know, if  both of them act the optimal way, what will be the difference between the number of her Magic Stones and the number of Bob's Magic Stones at the end of the game.
 

 

Input
  There are several cases(<=20).
  In each case, there are three integers at the first line: G, B, and S. Their meanings are mentioned above.
  Then B lines follow. Each line describes a bag in the following format:
  
  n c 1 c 2 ... c n
  
  It means that there are n Gems in the bag and their colors are color c 1,color c 2...and color c n respectively.
   0<=B<=21, 0<=G<=8, 0<n<=10, S < 20.
  There may be extra blank lines between cases. You can get more information from the sample input.
  The input ends with G = 0, B = 0 and S = 0.
 

 

Output
  One line for each case: the amount of Alice's Magic stones minus the amount of Bob's Magic Stones.
 

 

Sample Input
3 4 3 2 2 3 2 1 3 2 1 2 3 2 3 1 3 2 2 3 2 3 1 3 1 2 3 0 0 0
 

 

Sample Output
3 -3
Hint
  For the first case, in turn 2, bob has to choose at least one bag, so that Alice will make a Magic Stone at the end of turn 3, thus get turn 4 and get all the three Magic Stones.
 

 

Source

 

用dp[st]表示状态st下,用余下的未选的包裹能对当前先手做出的最大贡献。(即使当下的先手最大化其最终个数与对手的个数的差值)。末状态时显然贡献为0(双方均无包裹可再取)。而最初的的dp值显然需要由其产生的各种状况综合比较得到,故我们考虑逆向dp。每次先求出当前状态各种g余下的个数,对于下一个状况,统计加上后g的个数,设所有新的g共可以生成cnt个魔法石,如果cnt>0,则下一个状况的先手存在就是当下状况先手的可能,故用cnt+dp[st_new]更新,不然必改变了先手,用cnt-dp[st_new]更新。

 1 #include <iostream>
 2 #include <string>
 3 #include <algorithm>
 4 #include <cstring>
 5 #include <cstdio>
 6 #include <cmath>
 7 #include <queue>
 8 #include <set>
 9 #include <map>
10 #include <list>
11 #include <vector>
12 #include <stack>
13 #define mp make_pair
14 //#define P make_pair
15 #define MIN(a,b) (a>b?b:a)
16 //#define MAX(a,b) (a>b?a:b)
17 typedef long long ll;
18 typedef unsigned long long ull;
19 const int MAX=40;
20 const int INF=1e9+5;
21 using namespace std;
22 //const int MOD=1e9+7;
23 typedef pair<ll,int> pii;
24 const double eps=0.00000001;
25 int dp[1<<21];
26 int num[30][10];
27 int yu[10];//每种余下的数目
28 int trial[10];
29 int b,g,n,s,tem,cnt;
30 int main()
31 {
32     while(scanf("%d%d%d",&g,&b,&s)&&!(g==0&&b==0&&s==0))
33     {
34         memset(dp,0,sizeof(dp));
35         memset(num,0,sizeof(num));
36         for(int i=0;i<b;i++)
37         {
38             scanf("%d",&n);
39             for(int j=1;j<=n;j++)
40             {
41                 scanf("%d",&tem);
42                 ++num[i][tem];
43             }
44         }
45         int total=(1<<b)-1;
46         for(int i=1;i<=total;i++)
47         {
48             dp[i]=-INF;
49             memset(yu,0,sizeof(yu));
50             for(int j=0;j<b;j++)
51             {
52                 if(!(i&(1<<j)))
53                 {
54                     for(int q=1;q<=g;q++)
55                         yu[q]+=num[j][q];
56                 }
57             }
58             for(int q=1;q<=g;q++)
59                 yu[q]%=s;
60             for(int j=0;j<b;j++)
61             {
62                 if(i&(1<<j))
63                 {
64                     cnt=0;
65                     memcpy(trial,yu,sizeof(yu));
66                     for(int q=1;q<=g;q++)
67                     {
68                         trial[q]+=num[j][q];
69                         while(trial[q]>=s)
70                         {
71                             ++cnt;
72                             trial[q]-=s;
73                         }
74                     }
75                     if(cnt)
76                         dp[i]=max(dp[i],dp[i^(1<<j)]+cnt);
77                     else
78                         dp[i]=max(dp[i],-dp[i^(1<<j)]+cnt);
79                 }
80             }
81         }
82         printf("%d\n",dp[total]);
83     }
84 }

 

转载于:https://www.cnblogs.com/quintessence/p/7242342.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值