HDU

来源:互联网 发布:聚拓数据录入邀请码 编辑:程序博客网 时间:2024/06/14 13:56

传送门:HDU4778

题意:有 G 种颜色的宝石,放在 B 个袋子里,两人轮流选袋子(每个袋子只能被选 1 次),每次将选出来的袋子中的宝石放到 cooker 中,cooker 可能会起反应。
反应条件是 cooker 中出现至少 S 个一样颜色的宝石,而且一旦起反应,每 S 个一样颜色的宝石就会获得 1 个魔法石。
作为奖励,每次获得魔法石的玩家可以再选一个袋子继续游戏,若未获得魔法石,则轮到另一名玩家进行游戏。
游戏目标是使自己获得的魔法石尽量多,双方都采取最优策略的情况下,问最终两个玩家的魔法石之差。

思路:袋子最大数量为21,因此我们可以状压表示袋子的选取状态,袋子的选取状态相同,两玩家所能获得的总魔法石的数量是一定的,因此我们可以先预处理出来,然后记忆化搜索进行状态转移,转移的时候每次都针对先手的可能状态进行转移就好了,因为后手的得分我们可以通过用当前状态的总得分(预处理)减去先手得分求出。

代码:

#include<bits/stdc++.h>#define ll long long#define pi acos(-1)#define MAXN 100010#define inf 0x3f3f3f3fusing namespace std;typedef pair<int,int>P;int G, B, S, n; int bag[30][30];int score[1 << 21], dp[1 << 21];void init(){int up = 1 << B, cnt;int sum[30] = {0};for(int i = 0; i < up; i++){for(int j = 0; j < B; j++){if(i >> j & 1) continue;for(int k = 1; k <= G; k++)sum[k] += bag[j][k];}cnt = 0;for(int j = 1; j <= G; j++){cnt += sum[j] / S;sum[j] = 0;}score[i] = cnt;}}int dfs(int status)//先手的状态为status所能获得的最大分数 {if(dp[status] != -1) return dp[status];int tmp, delta, ans = 0;for(int i = 0; i < B; i++){if(status >> i & 1){tmp = status ^ (1 << i);delta = score[tmp] - score[status];if(delta) ans = max(ans, delta + dfs(tmp));else ans = max(ans, score[0] - score[status] - dfs(tmp)); }}return dp[status] = ans;} int main(){int t;while(scanf("%d %d %d", &G, &B, &S), G + B + S){memset(dp, -1, sizeof(dp));memset(bag, 0, sizeof(bag));memset(score, 0, sizeof(score));for(int i = 0; i < B; i++){scanf("%d", &n);while(n--){scanf("%d", &t);bag[i][t]++;}}init();int alice = dfs((1 << B) - 1);printf("%d\n", alice - (score[0] - alice));}    return 0;}

另一种实现方法:点击打开链接

原创粉丝点击