Time Limit: 20000/10000 MS (Java/Others)    Memory Limit: 327680/327680 K (Java/Others)

Total Submission(s): 1912    Accepted Submission(s): 824


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

  

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

 
这是一题状压dp+记忆化搜索,因为每一个人都要走最优的方案,所以这样的方案只有一种,我们用二进制表示背包的状态,因为如果背包的状态确定的话,那么得到的总分数是一定的,如果一个人想赢,一定是尽可能的使得自己的得分大于对方,即分差尽量大,可以从后往前推,这样推到当前状态才知道哪个是最优的,。可以用dp[state]表示当前背包状态是state时,先手与后手的最大分数差,这样就可以转移了。

#include<iostream>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<vector>
#include<map>
#include<set>
#include<queue>
#include<stack>
#include<string>
#include<algorithm>
using namespace std;
typedef long long ll;
#define inf 99999999
int dp[4200000][2];
int vis[4200000];
int num[30][30];
int p[10]; //把p[]设为全局变量,这样dfs中的一个层改变,总体也改变了
int tot,g,b,s; void dfs(int state,int turn)
{
int i,j,st,turn1;
int pp[10];
if( state==(1<<b)-1 ){
dp[state][0]=dp[state][1]=0;
return;
}
if(vis[state])return;
dp[state][1]=0;
dp[state][0]=-inf;
int cha=-inf;
for(j=1;j<=8;j++){ //这里要先把p[]备份,因为还要回溯
pp[j]=p[j];
}
for(i=1;i<=b;i++){
int t1=0;
int t2=0;
if(state&(1<<(i-1)) )continue; //这里要选择一个当前状态没有选择过的背包
st=state|(1<<(i-1) );
int cnt=0;
for(j=1;j<=g;j++){
p[j]+=num[i][j];
cnt+=p[j]/s;
p[j]%=s;
}
if(cnt==0){
turn1=1^turn; //这里表示是不是要换成对手拿
}
else turn1=turn;
dfs(st,turn1);
for(j=1;j<=8;j++){
p[j]=pp[j];
}
t1+=cnt;
if(cnt==0){ //如果交换了,那么先手t1的值要加上st状态后手拿的最大值
t1+=dp[st][1];
t2+=dp[st][0];
}
else{
t1+=dp[st][0];
t2+=dp[st][1];
}
if(t1-t2>cha){
cha=t1-t2;
dp[state][0]=t1;
dp[state][1]=t2;
}
}
vis[state]=1; //访问过的状态就不用访问了,相当于剪枝
return ;
} int main()
{
int n,m,i,j,c,t;
while(scanf("%d%d%d",&g,&b,&s)!=EOF)
{
if(g==0 && b==0 && s==0)break;
memset(num,0,sizeof(num));
for(i=1;i<=b;i++){
scanf("%d",&t);
for(j=1;j<=t;j++){
scanf("%d",&c);
num[i][c]++;
}
}
memset(p,0,sizeof(p));
memset(vis,0,sizeof(vis));
dfs(0,0);
printf("%d\n",dp[0][0]-dp[0][1]);
}
return 0;
}

也可以用状压dp,用dp[state]表示在state状态下先手与后手的最大差距。

#include<iostream>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
#include<vector>
#include<map>
#include<set>
#include<queue>
#include<stack>
#include<string>
#include<algorithm>
using namespace std;
typedef long long ll;
typedef long double ldb;
#define inf 99999999
#define pi acos(-1.0)
#define maxn 15
int a[25][22],dp[1<<23];
int color[25],color1[25]; int main()
{
int n,m,i,j,T,G,B,S,c,state;
while(scanf("%d%d%d",&G,&B,&S)!=EOF)
{
if(G==0 && B==0 && S==0)break;
memset(a,0,sizeof(a));
for(i=1;i<=B;i++){
scanf("%d",&n);
for(j=1;j<=n;j++){
scanf("%d",&c);
a[i][c]++;
}
}
dp[0]=0;
for(state=1;state<(1<<B);state++){
dp[state]=-inf;
for(i=1;i<=G;i++)color[i]=0;
for(i=1;i<=B;i++){
if((state&(1<<(i-1) ))==0 ){
for(j=1;j<=G;j++){
color[j]+=a[i][j];
color[j]=color[j]%S;
}
}
}
for(i=1;i<=B;i++){
if(state&(1<<(i-1) )){
int state1=(state^(1<<(i-1) ) );
for(j=1;j<=G;j++)color1[j]=color[j];
int cnt=0;
for(j=1;j<=G;j++){
color1[j]+=a[i][j];
cnt+=color1[j]/S;
}
if(cnt!=0) dp[state]=max(dp[state],dp[state1]+cnt);
else dp[state]=max(dp[state],-dp[state1]); //这里没有产生魔法石,所以先后手互换
}
}
}
printf("%d\n",dp[(1<<B)-1]);
}
return 0;
}


hdu4778 Gems Fight!的更多相关文章

  1. hdu 4778 Gems Fight! 博弈+状态dp+搜索

    作者:jostree 转载请注明出处 http://www.cnblogs.com/jostree/p/4102743.html 题目链接:hdu 4778 Gems Fight! 博弈+状态dp+搜 ...

  2. hdu 4778 Gems Fight! 状态压缩DP

    Gems Fight! Time Limit: 20000/10000 MS (Java/Others)    Memory Limit: 327680/327680 K (Java/Others)T ...

  3. HDU 4778 Gems Fight! (2013杭州赛区1009题,状态压缩,博弈)

    Gems Fight! Time Limit: 20000/10000 MS (Java/Others)    Memory Limit: 327680/327680 K (Java/Others)T ...

  4. Hdu 4778 Gems Fight! (状态压缩 + DP)

    题目链接: Hdu 4778 Gems Fight! 题目描述: 就是有G种颜色,B个背包,每个背包有n个宝石,颜色分别为c1,c2............两个人轮流取背包放到公共容器里面,容器里面有 ...

  5. HDU 4778 Gems Fight!(DP)

    题目链接 当我放弃的时候过了.sb啊,卡常数!!! 换了好几个姿势,本来没写预处理,预处理+俩剪枝,尼玛就过了.. #include <stdio.h> #include <stri ...

  6. hdu 4778 Gems Fight! 状压dp

    转自wdd :http://blog.csdn.net/u010535824/article/details/38540835 题目链接:hdu 4778 状压DP 用DP[i]表示从i状态选到结束得 ...

  7. hdu 4778 Gems Fight!

    第一次写状压dp-- 题意:http://blog.csdn.net/dyx404514/article/details/15506601 状压dp+博弈吧-- #include<iostrea ...

  8. Unable to download data from http://ruby.taobao.org/ & don't have write permissions for the /Library/Ruby/Gems/2.0.0 directory.

    安装cocoapods,记录两个问题! 1.镜像已经替换成了 http://ruby.taobao.org/, 还是不能不能安装cocoapods, 报错:Unable to download dat ...

  9. Australian troops to the fight against Islamic State militants.

    He arrived in Arnhem Land on Sunday, honouring an election promise to spend a week every year in an ...

随机推荐

  1. Flutter 布局类组件:弹性布局(Flex)

    前言 弹性布局允许子组件按照一定比例来分配父容器空间,Flutter中的弹性布局主要通过Flex和Expanded来配合实现. Flex Flex组件可以沿着水平或垂直方向排列子组件,如果你知道主轴方 ...

  2. DTCC 2020 | 阿里云李飞飞:云原生分布式数据库与数据仓库系统点亮数据上云之路

    简介: 数据库将面临怎样的变革?云原生数据库与数据仓库有哪些独特优势?在日前的 DTCC 2020大会上,阿里巴巴集团副总裁.阿里云数据库产品事业部总裁.ACM杰出科学家李飞飞就<云原生分布式数 ...

  3. 一文带你探究Sentinel的独特初始化

    摘要:本系列通过作者对Redis Sentinel源码的理解,详细说明Sentinel的代码实现方式. Redis Sentinel 是Redis提供的高可用模型解决方案.Sentinel可以自动监测 ...

  4. PAT甲级 1155 Heap Paths (30分) 堆模拟

    题意分析: 给出一个1000以内的整数N,以及N个整数,并且这N个数是按照完全二叉树的层序遍历输出的序列,输出所有的整条的先序遍历的序列(根 右 左),以及判断整棵树是否是符合堆排序的规则(判断是大顶 ...

  5. 【Java】标识符

    一.标识符 文章目录 一.标识符 1.标识符的命名规则 2.关键字.保留字.特殊值 3.code Java 对各种变量.方法和类等要素命名时使用的字符序列称为标识符.简单的说,凡是程序员自己命名的部分 ...

  6. Restful API是什么、为什么、怎么使用

    Restful API 文章目录 Restful API 1.REST是什么以及它的 6 个限制 REST是什么? REST的6个限制 2. Restful是什么 Restful是什么 RESTful ...

  7. linux7下修改主机名的方式

    在基于linux发行版的众多linux kernel 3.0以上,包括rhel7,centos7等提供多种修改linux主机名的方式 1.通过编辑/etc/hostname文件 2.命令hostnam ...

  8. 算法模板 - C++ 高精度运算

    C++算法板子 高精度 高精度推荐用python来写,python有大整数,这里写的是关于C++的高精度运算模板 1.高精 * 低精 #include <iostream> #includ ...

  9. centos&linux

    who am i 查看是哪一个用户 init 0关机 ifconfig用于配置网络或显示当前网络接口的状态 eth0是网卡的名字 第一行:flags后面的up指的是网卡处于运行状态,running连接 ...

  10. 转 7 jmeter之参数化

    7 jmeter之参数化   badboy里参数化(前面4 jmeter badboy脚本开发技术详解已讲过) jmeter里参数化-1 用户参数 1.打开badboy工具,点击红色按钮开始录制,在地 ...