Gems Fight! (状压dp)

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 c1 c2 . . . cn

It means that there are n Gems in the bag and their colors are color c1, color c2 ...and color cnrespectively (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.

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.

 

题意:
有G种颜色的宝石,有B个袋子,每个袋子里有各种颜色的宝石若干,有一个cooker 
两个人轮流选一个袋子,将袋子里面的宝石全部丢到cooker里面,如果cooker里面某种颜色的宝石达到数量S就会melt成魔石
而这个操作的人就会得到魔石,而得到魔石的人可以额外获得一次选袋子的机会
现在给出G B S和每个袋子里面宝石的情况,求当2个人都选择最优的策略的时候,先手的最大收益
这里的收益指先手获得的魔石数减去后手的魔石数,所以这个收益可能是负的
分析:
首先明确一点,这题是博弈!博弈!博弈!就因为那一句“双方选取最优策略”
博弈的显著特点就是双方选择最优策略,就因为这一点,在游戏过程中,(copy)

题解:状压dp,dp[sta]表示面对sta状态时,该人能获得的最大利益, 1表示已取,0表示没取。

//#include"bits/stdc++.h"
//#include<unordered_map>
//#include<unordered_set>
#include<iostream>
#include<sstream>
#include<iterator>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<string>
#include<set>
#include<vector>
#include<bitset>
#include<climits>
#include<queue>
#include<iomanip>
#include<cmath>
#include<stack>
#include<map>
#include<ctime>
#include<new>
using namespace std;
#define LL long long
#define ULL unsigned long long
#define MT(a,b) memset(a,b,sizeof(a))
#define lson l, mid, node << 1
#define rson mid + 1, r, node << 1 | 1
const int INF  =  0x3f3f3f3f;
const int O    =  1e6;
const int mod  =  10007;
const int maxn =  1e5+5;
const double PI  =  acos(-1.0);
const double E   =  2.718281828459;

const int _ = 1;
const int __ = 2;
const int ___ = 3;

int dp[1<<21];

int main(){
    int C, N, K;
    while( ~scanf("%d%d%d", &C, &N, &K) && C + N + K){
        
        int bag[30][30]; MT(bag, 0);
        for(int i=0; i<N; i++) {
            int k; scanf("%d", &k);
            while(k --) {
                int col; scanf("%d", &col);
                bag[i][col] ++;
            }
        }
        
        dp[(1<<N)-1] = 0;
        for(int sta = (1<<N)-2; sta >= 0; sta --) {
            dp[sta] = -INF;
            int cook[30]; MT(cook, 0); //计算sta下cook的颜色状态
            for(int i=0; i<N; i++) {
                if(sta & (1<<i)) for(int col=1; col<=C; col++)
                    cook[col] = (cook[col] + bag[i][col]) % K;
            }
            for(int i=0; i<N; i++) {
                if(! (sta & (1<<i))) {
                    int get = 0; // 计算添加下一个bag后能的到的宝石数量
                    for(int col=1; col<=C; col ++)
                        get += (cook[col] + bag[i][col]) / K;
                    if(get) dp[sta] = max(dp[sta], get + dp[sta ^ (1<<i)]);
                    else dp[sta] = max(dp[sta], - dp[sta ^ (1<<i)]);
                }
            }
        }
        
        printf("%d\n", dp[0]);
    }
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值