ICPC山东省赛 H.Adventurer's Guild
题目链接:Adventurer's Guild
-
题意:主角拥有H值和S值,每个怪兽有一个h值hi和s值si,消灭一个怪兽主角需要花费hi和si,此时主角的H值变为H-hi,S值变为S-si,若S值不够减si,可以拿H值进行替补,但必须保证H值始终大于0,消灭一个怪兽会得到w的价值,求最大w之和。
-
思路:01背包变型 + 滚动数组优化
-
解析:
- 集合划分:dp[i][j][k]表示前i个怪兽消耗j的h值和k的s值可获得最大w。
- 状态表示:
- 不选择第i个怪兽:dp[i][j][k] = dp[i-1][j][k]
- 当 j > a[i].h && j + k > a[i].h + a[i].s(主角的H值 > 该怪兽的h值并且主角的H值 + S值得 > 该怪兽的h值 + s值)ps: 不能写成j > a[i].h && j + k > a[i].s(因为若此时主角的S值小于怪兽的s值,则需要H给S进行替补,替补后可能H就小于h,此时H可能小于等于0不满足题目条件)
选择第i个怪兽:[注意防止数组越界]
dp[i-1][j-a[i].h][k-a[i].s] + a[i].w)(k >= a[i].s)
dp[i-1][j - a[i].h - (a[i].s - k)][0] + a[i].w)(k < a[i].s)
-
代码:
#include<iostream>
using namespace std;
typedef long long ll;
const int N = 1005;
const int M = 305;
ll dp[N][M][M];
ll n, h, s;
struct Node
{
ll h, s, w;
}a[N];
int main()
{
cin >> n >> h >> s;
for(int i = 1; i <= n; i++)
cin >> a[i].h >> a[i].s >> a[i].w;
for(int i = 1; i <= n; i++)
{
for(int j = 1; j <= h; j++)
{
for(int k = 0; k <= s; k++)
{
dp[i][j][k] = dp[i-1][j][k];
if(j > a[i].h && j + k > a[i].s + a[i].h)
{
if(k >= a[i].s) dp[i][j][k] = max(dp[i][j][k], dp[i-1][j-a[i].h][k-a[i].s] + a[i].w);
else dp[i][j][k] = max(dp[i][j][k], dp[i-1][j - a[i].h - (a[i].s - k)][0] + a[i].w);
}
}
}
}
cout << dp[n][h][s] << endl;
return 0;
}
但是上面的代码会MLE,所以用滚动数组的思想进行优化成二维数组即可。
- 代码:
#include<iostream>
using namespace std;
typedef long long ll;
const int N = 1005;
const int M = 305;
ll dp[M][M];
ll n, h, s;
struct Node
{
ll h, s, w;
}a[N];
int main()
{
cin >> n >> h >> s;
for(int i = 1; i <= n; i++)
cin >> a[i].h >> a[i].s >> a[i].w;
for(int i = 1; i <= n; i++)
{
for(int j = h; j > a[i].h; j--)
{
for(int k = s; k >= 0; k--)
{
if(j + k > a[i].s + a[i].h)
{
if(k >= a[i].s) dp[j][k] = max(dp[j][k], dp[j-a[i].h][k-a[i].s] + a[i].w);
else dp[j][k] = max(dp[j][k], dp[j - a[i].h - (a[i].s - k)][0] + a[i].w);
}
}
}
}
cout << dp[h][s] << endl;
return 0;
}

浙公网安备 33010602011771号