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