HDU4778 Gems Fight!(记忆化搜索+博弈)

传送门: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;
}


你可能感兴趣的:(HDU4778 Gems Fight!(记忆化搜索+博弈))