Gym 101161H Witcher Potion 【状压dp】

题意:勇者去打怪兽,有两个值,一个是能量条,初始100,debuff毒素条,一开始0。每个样例的第一行是打一个怪兽需要的能量和时间。第二行是勇者带的药的瓶数。接下来一行给的是每瓶药可以加的能量,然后一行是每瓶药会增加的毒素值。每次打完怪,勇者可以喝最多一瓶药,或者不喝。当勇者能量<=打怪需要的能量的时候,就不能开怪了,不能开怪就结束了,还有毒素,超过100他也死了。打怪的时候,过多少时间,-多少毒素值,毒素值最低0,能量最多100。

思路:首先注意一下debuff毒素条最多99,100就gg了,训练写这题的时候我以为是最多100,结果wa了,被队友吐槽死了QAQ

然后由于最多8瓶药,就考虑状压一下喝药状态。然后还有两维放能量和毒素,最后一维放这一场boss战喝没喝药,然后暴力跑dp就行了。

代码:

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
const int maxn = 110;
const int inf = 0x3f3f3f3f;

int c,kk,m,n,dp[1<<9][maxn][maxn][2];
struct node
{
	int en, po;
}med[10];

int main()
{
	scanf("%d", &c);
	while (c--)
	{
		scanf("%d %d", &kk, &m);
		scanf("%d", &n);
		for (int i = 1; i <= n; i++)
		{
			scanf("%d", &med[i].en);
		}
		for (int i = 1; i <= n; i++)
		{
			scanf("%d", &med[i].po);
		}
		memset(dp, -inf, sizeof(dp));
		dp[0][100][0][0] = 0;
		int A = 0;
		for (int i = 0; i <= (1 << n) - 1; i++)
		{
			for (int j = 100; j >= 1; j--)
			{
				for (int k = 99; k >= 0; k--)
				{
					for (int q = 0; q <= 1; q++)
					{
						if (dp[i][j][k][q] < 0)
							continue;
						if (j > kk)//能量足够打败怪兽
						{
							dp[i][j-kk][max(0,k-m)][0] = max(dp[i][j][k][q]+1, dp[i][j - kk][max(0, k - m)][0]);
							A = max(A, dp[i][j - kk][max(0, k - m)][0]);
						}
						if (q == 1)
							continue;
						for (int w = 1; w <= n; w++)
						{
							int id = 1 << (w - 1);
							if (id&i || k + med[w].po >= 100)//吃过或者毒素>=100
								continue;
							int now = id | i;
							dp[now][min(100,j+med[w].en)][k+med[w].po][1] = max(dp[now][min(100, j + med[w].en)][k + med[w].po][1], dp[i][j][k][q]);
							A = max(A, dp[now][min(100, j + med[w].en)][k + med[w].po][1]);
						}
					}
				}
			}
		}
		printf("%d\n", A);
	}
	return 0;
}

 

你可能感兴趣的:(状压dp)