您的位置:首页 > 其它

7_11_I题 Gems Fight!(状压dp)

2016-09-04 15:37 337 查看

7_11_I题 Gems Fight!(状压dp)

简单题意

有G种颜色的宝石放在B个包里,两人轮流拆包,把里面的宝石取出放到一个锅里,如果有S个相同颜色的宝石,他们就会融合成一个魔法石,如果得到了新的魔法石,当前的操作员可以获得额外一次的操作机会,问两人都在最优取法下,两人的分差是多少

思路

因为两人是共用一个锅,且两人都是最优取法,所以两人的取法实际是固定的,最后得到的魔法石的总数也是固定的,可以用一个二进制数来表示当前包被打开的状态。然后dp[statue]表示包的打开状态为statue时,先手的人获得的魔法石数,设下次选择能构成N个魔法石(这个可以预处理出来)

遍历出所有的next_statue

如果 N > 0,则不换人:

dp[statue]=max(dp[s<
4000
span class="mi" id="MathJax-Span-162" style="font-family: MathJax_Math-italic;">tatue],dp[next_statue]+N)

否则 换人:设剩余状态可获取的魔法石数为P

dp[statue]=max(dp[statue],P−dp[next_statue])

预处理出所有状态的剩余可获取魔法石数,再记忆化搜索一下就行了。

代码

#include <bits/stdc++.h>

using namespace std;

const int  maxn = 1 << 21;
int n;
int dp[maxn], score[maxn];
int a[25][10],sum[10];

int dfs(int statue){
int res = 0;
if(dp[statue]) return dp[statue];
for(int i = 0; i < n; i++)
if(statue & (1<<i)){
int next_statue = statue ^ (1 << i);
int dif = score[next_statue] - score[statue];
if(dif > 0) //有融合,不换人
res = max(res, dif + dfs(next_statue));
else {//没有融合换人
int le = score[0] - score[statue];//剩下的分数
res = max(res, le - dfs(next_statue));
}
}
return dp[statue] = res;
}

int main(){
int g,s;
while(~scanf("%d%d%d", &g, &n, &s) && g){
memset(a, 0, sizeof a );
memset(dp, 0 , sizeof dp);
for(int i = 0; i < n; i++){
int t, co;
scanf("%d", &t);
while(t--){
scanf("%d", &co);
a[i][co]++;
}
}
for(int statue = 0; statue < (1 << n); statue++){
memset(sum, 0, sizeof(sum));
for(int i = 0; i < n; i++)
if((statue & (1<<i)) ^ (1 << i))
for(int k = 1; k <= g; k++)
sum[k] += a[i][k];

score[statue] = 0;
for(int i = 1; i <= g; i++)
score[statue] += sum[i] / s;
}
printf("%d\n", 2 * dfs((1 << n) - 1) - score[0]);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: