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;
}
posted @ 2017-09-14 23:30  Lweleth  阅读(125)  评论(0编辑  收藏  举报