HDU 4778 状压DP
一看就是状压,由于是类似博弈的游戏。游戏里的两人都是绝对聪明,那么先手的选择是能够确定最终局面的。 实际上是枚举最终局面情况,0代表是被Bob拿走的,1为Alice拿走的,当时Alice拿走且满足变换成魔法石,那么相当于是Alice完成了该次操作,增加上次状态值,否则相当于先后手交换,该状态下减去上个状态值。
/** @Date : 2017-09-12 23:51:53 * @FileName: HDU 4778 状压DP 或 记忆化 好题.cpp * @Platform: Windows * @Author : Lweleth (SoungEarlf@gmail.com) * @Link : https://github.com/ * @Version : $Id$ */ #include <bits/stdc++.h> #define LL long long #define PII pair #define MP(x, y) make_pair((x),(y)) #define fi first #define se second #define PB(x) push_back((x)) #define MMG(x) memset((x), -1,sizeof(x)) #define MMF(x) memset((x),0,sizeof(x)) #define MMI(x) memset((x), INF, sizeof(x)) #define MMN(x) memset((x), -INF, sizeof(x)) using namespace std; const int INF = 0x3f3f3f3f; const int N = 1e5+20; const double eps = 1e-8; int G, B, n, S; int cl[25][10]; int dp[(1 << 21) + 20]; int main() { while(~scanf("%d%d%d", &G, &B, &S) && (G || B || S)) { MMF(cl); for(int i = 0; i < B; i++) { scanf("%d", &n); for(int j = 0; j < n; j++) { int x; scanf("%d", &x); cl[i][x]++; } } MMN(dp); dp[0] = 0; for(int stat = 1; stat < (1 << B); stat++) { int cnt[10]={0}; for(int j = 0; j < B; j++) { if((stat & (1 << j)) == 0) { for(int k = 1; k <= G; k++) cnt[k] = (cnt[k] + cl[j][k]) % S; } } for(int j = 0; j < B; j++) { if((stat & (1 << j))) { int flag = 0; for(int k = 1; k <= G; k++) flag += (cnt[k] + cl[j][k])/S; if(flag) dp[stat] = max(dp[stat], dp[stat ^ (1 << j)] + flag); else dp[stat] = max(dp[stat], -dp[stat ^ (1 << j)]); } } } printf("%d\n", dp[(1<<B) - 1]); } return 0; }