HDU4778 Gems Fight!(记忆化搜索+博弈)
2015-10-13 22:22
190 查看
传送门:http://acm.hdu.edu.cn/showproblem.php?pid=4778
题目大意:有B个包裹,里面有各种颜色的GEM,共有G个颜色。Alice和Bob轮流挑选包裹放到一个地方,如果挑选出来的同种颜色的GEM超过S个,当前回合者可以得分,每超过S个得一分。如果在回合内得分了,可以额外进行一个回合。问Alice的得分减去Bob的得分最大是多少。
#include<iostream>
#include<algorithm>
#include<string>
#include<map>//ll dx[4]={0,0,-1,1};ll dy[4]={-1,1,0,0};
#include<set>//
#include<vector>
#include<cmath>
#include<stack>
#include<string.h>
#include<stdlib.h>
#include<cstdio>
#define mod 1e9+7
#define ll long long
using namespace std;
#define REP(i,n) for(int i=0;i<(n);++i)
struct node {
int c[10]; //一个包里某颜色个数
}Bag[30];
int b,g,s,now[10],sg[1<<22];
int judge(int k){
int total = 0;
REP(i,g+1){
now[i]+=Bag[k].c[i];
total+=now[i]/s; //每超过s个得一分
now[i]%=s; //该颜色(i)剩下的个数
}
return total; //返回得到的分数
}
int dfs(int dp){
if(sg[dp] != -1)
return sg[dp];
int tep[10],ans = -100000000; //结果有可能是负的
for(int i=1;i<=g;++i)
tep[i] = now[i]; //now[i]表示现在第i种颜色的有几个了
for(int i=0;i<b;++i){ //遍历背包
int k = 1 << i;
if(!(dp & k)){ //dp这个状态里第k个包没取
int total = judge(i); //判断当前这个人能得多少分
if(total > 0) //得分了
ans = max(ans,total + dfs(dp|k)); //下一轮还是自己选 ,dp|k表示算取了第k个包
else
ans = max(ans,total - dfs(dp|k)); //下一轮对方选
for(int j=1;j<=g;++j)
now[j] = tep[j]; //注意,每进行一次上面的dfs,now[]值会变
}
}
return sg[dp] = ans;
}
void init() {
int k = 1 << b;
memset(sg,-1,sizeof(sg));
sg[k-1] = 0; //记忆化搜索最终状态,所有包都取完
memset(now,0,sizeof(now));
memset(Bag,0,sizeof(Bag));
}
int main() {
int n,m,t,cs=0;
while(~scanf("%d%d%d",&g,&b,&s)) { //颜色数、包裹数、回合数
if(!b && !g && !s)
break;
init();
REP(i,b){
scanf("%d",&n); //第i个包裹里有n种颜色
while(n--){
scanf("%d",&m); //颜色编号
Bag[i].c[m]++;
}
}
printf("%d\n",dfs(0)); //0表示一个包都没取的状态
}
return 0;
}
#include<iostream>
#include<algorithm>
#include<string>
#include<map>//int dx[4]={0,0,-1,1};int dy[4]={-1,1,0,0};
#include<set>//
#include<vector>
#include<cmath>
#include<stack>
#include<string.h>
#include<stdlib.h>
#include<cstdio>
#define mod 1e9+7
#define ll long long
using namespace std;
struct node{
int c[10];
}x[30];
int g,b,k,m,a;
int now[30];
int dp[(1<<22)];
int ss;
int dfs(int p){
if(dp[p]!=-1)
return dp[p];
int tmp[10]; //注意是内部函数,需要定义在里面
for(int i=1;i<=g;++i){
tmp[i]=now[i];
}
int ss=-10000000;
for(int i=0;i<b;++i){
if(p&(1<<i))
continue;
int cnt=0;
for(int j=1;j<=g;++j){
now[j]+=x[i].c[j];
cnt+=now[j]/k;
now[j]%=k;
}
if(cnt>0)
ss=max(ss,cnt+dfs(p|(1<<i)));
else
ss=max(ss,cnt-dfs(p|(1<<i)));
for(int j=1;j<=g;++j)
now[j]=tmp[j];
}
dp[p]=ss;
return dp[p];
}
int main(){
while(cin>>g>>b>>k){
if(g+b+k==0)
break;
memset(x,0,sizeof(x));
memset(now,0,sizeof(now));
for(int i=0;i<b;++i){
cin>>m;
for(int j=0;j<m;++j){
cin>>a;
x[i].c[a]++;
}
}
memset(dp,-1,sizeof(dp));
dp[(1<<b)-1]=0;
cout<<dfs(0)<<endl;
}
return 0;
}
题目大意:有B个包裹,里面有各种颜色的GEM,共有G个颜色。Alice和Bob轮流挑选包裹放到一个地方,如果挑选出来的同种颜色的GEM超过S个,当前回合者可以得分,每超过S个得一分。如果在回合内得分了,可以额外进行一个回合。问Alice的得分减去Bob的得分最大是多少。
#include<iostream>
#include<algorithm>
#include<string>
#include<map>//ll dx[4]={0,0,-1,1};ll dy[4]={-1,1,0,0};
#include<set>//
#include<vector>
#include<cmath>
#include<stack>
#include<string.h>
#include<stdlib.h>
#include<cstdio>
#define mod 1e9+7
#define ll long long
using namespace std;
#define REP(i,n) for(int i=0;i<(n);++i)
struct node {
int c[10]; //一个包里某颜色个数
}Bag[30];
int b,g,s,now[10],sg[1<<22];
int judge(int k){
int total = 0;
REP(i,g+1){
now[i]+=Bag[k].c[i];
total+=now[i]/s; //每超过s个得一分
now[i]%=s; //该颜色(i)剩下的个数
}
return total; //返回得到的分数
}
int dfs(int dp){
if(sg[dp] != -1)
return sg[dp];
int tep[10],ans = -100000000; //结果有可能是负的
for(int i=1;i<=g;++i)
tep[i] = now[i]; //now[i]表示现在第i种颜色的有几个了
for(int i=0;i<b;++i){ //遍历背包
int k = 1 << i;
if(!(dp & k)){ //dp这个状态里第k个包没取
int total = judge(i); //判断当前这个人能得多少分
if(total > 0) //得分了
ans = max(ans,total + dfs(dp|k)); //下一轮还是自己选 ,dp|k表示算取了第k个包
else
ans = max(ans,total - dfs(dp|k)); //下一轮对方选
for(int j=1;j<=g;++j)
now[j] = tep[j]; //注意,每进行一次上面的dfs,now[]值会变
}
}
return sg[dp] = ans;
}
void init() {
int k = 1 << b;
memset(sg,-1,sizeof(sg));
sg[k-1] = 0; //记忆化搜索最终状态,所有包都取完
memset(now,0,sizeof(now));
memset(Bag,0,sizeof(Bag));
}
int main() {
int n,m,t,cs=0;
while(~scanf("%d%d%d",&g,&b,&s)) { //颜色数、包裹数、回合数
if(!b && !g && !s)
break;
init();
REP(i,b){
scanf("%d",&n); //第i个包裹里有n种颜色
while(n--){
scanf("%d",&m); //颜色编号
Bag[i].c[m]++;
}
}
printf("%d\n",dfs(0)); //0表示一个包都没取的状态
}
return 0;
}
#include<iostream>
#include<algorithm>
#include<string>
#include<map>//int dx[4]={0,0,-1,1};int dy[4]={-1,1,0,0};
#include<set>//
#include<vector>
#include<cmath>
#include<stack>
#include<string.h>
#include<stdlib.h>
#include<cstdio>
#define mod 1e9+7
#define ll long long
using namespace std;
struct node{
int c[10];
}x[30];
int g,b,k,m,a;
int now[30];
int dp[(1<<22)];
int ss;
int dfs(int p){
if(dp[p]!=-1)
return dp[p];
int tmp[10]; //注意是内部函数,需要定义在里面
for(int i=1;i<=g;++i){
tmp[i]=now[i];
}
int ss=-10000000;
for(int i=0;i<b;++i){
if(p&(1<<i))
continue;
int cnt=0;
for(int j=1;j<=g;++j){
now[j]+=x[i].c[j];
cnt+=now[j]/k;
now[j]%=k;
}
if(cnt>0)
ss=max(ss,cnt+dfs(p|(1<<i)));
else
ss=max(ss,cnt-dfs(p|(1<<i)));
for(int j=1;j<=g;++j)
now[j]=tmp[j];
}
dp[p]=ss;
return dp[p];
}
int main(){
while(cin>>g>>b>>k){
if(g+b+k==0)
break;
memset(x,0,sizeof(x));
memset(now,0,sizeof(now));
for(int i=0;i<b;++i){
cin>>m;
for(int j=0;j<m;++j){
cin>>a;
x[i].c[a]++;
}
}
memset(dp,-1,sizeof(dp));
dp[(1<<b)-1]=0;
cout<<dfs(0)<<endl;
}
return 0;
}
相关文章推荐
- hdu 4568 hunter
- select、poll、epoll之间的区别总结
- eclipse插件启动Genymotion模拟器失败解决方案
- poj 3253 Fence Repair
- abstract interface区别
- leetcode-44 Wildcard Matching 通配符匹配
- HTTP/1.1与HTTP/1.0的区别
- 10.13 js入门
- C++中String类的实现
- 【特种兵PPT教程】簇状柱形图你用对了吗?
- 交叉验证
- iOS 键盘回收实现步骤
- Android官方API Guide学习之二 设备兼容性
- C语言数据结构-树
- Android 五大布局之(一) 线性布局和相对布局
- 编译错误 error C2451: “std::_Unforced”类型的条件表达式是非法的
- 转!!数据库 第一范式(1NF) 第二范式(2NF) 第三范式(3NF)的 联系和区别
- 工厂模式、控制反转及依赖注入
- 第 二 十 九 天:监 控 软 件 之 zabbix
- hadoop 数据挖掘