给出G种宝石,B个包,和S,S代表到时候每种颜色的宝石凑齐S个能变成一个魔法石
每个包里有N种宝石,分别为c1,c2.......
然后两人轮流拿包,每个包只能拿一次,拿出包把宝石放地上。
如果能变成魔法石则拿走魔法石,下一次还这个人拿包,没变成则换人。
魔法石的个数就是获得分数,问两人最优的时候分差是多少。
状压记忆化搜索
一共21个包,状压存当前取包的状态
无论怎样取,最后获得的魔法石数量一定
dp[i]表示在i状态下,先手可以获得的最高分数
#include "stdio.h" #include "string.h" int aim,g,b,s; int dp[1<<22],c[25][10]; int bit[25]; int inf=0x3f3f3f3f; int Max(int a,int b) { if (a<b)return b; else return a; } int dfs(int cur,int sum,int temp[]) { int ans,i,next,j,w,cnt; int mark[10]; if (cur==aim || sum==0) return 0; if (dp[cur]!=inf) return dp[cur]; ans=0; for (i=1;i<=b;i++) if (cur&bit[i]) { next=cur^bit[i]; cnt=0; for (j=1;j<=g;j++) { mark[j]=temp[j]+c[i][j]; cnt+=mark[j]/s; mark[j]%=s; } if (cnt>0) w=cnt+dfs(next,sum-cnt,mark); else w=sum-dfs(next,sum,mark); ans=Max(ans,w); } return dp[cur]=ans; } int main() { int i,n,x,sum,aim,ans; int all[10],mark[25]; bit[1]=1; for (i=2;i<=22;i++) bit[i]=bit[i-1]*2; while (scanf("%d%d%d",&g,&b,&s)!=EOF) { if (g+b+s==0) break; memset(c,0,sizeof(c)); memset(all,0,sizeof(all)); for (i=1;i<=b;i++) { scanf("%d",&n); while (n--) { scanf("%d",&x); c[i][x]++; all[x]++; } } sum=0; for (i=1;i<=g;i++) sum+=all[i]/s; aim=bit[b+1]-1; memset(mark,0,sizeof(mark)); memset(dp,inf,sizeof(dp)); ans=dfs(0,0,mark); printf("%d\n",ans-(sum-ans)); } return 0; }
时间: 2024-10-15 04:58:18