E - Crested Ibis vs Monster

本文介绍了一种如何利用动态规划解决Atcoder竞赛题目中的E-CrestedIbis与怪兽战斗问题,涉及计算在给定条件下消灭怪兽所需的最小总魔法点数。通过构建二维数组和状态转移方程,求解了消灭怪兽的不同策略下的最优魔法消耗。
摘要由CSDN通过智能技术生成

E - Crested Ibis vs Monster (atcoder.jp)

原题

Problem Statement Ibis is fighting with a monster.

The health of the monster is H.

Ibis can cast N kinds of spells. Casting the i-th spell decreases the monster's health by A i​, at the cost of B i​Magic Points.

The same spell can be cast multiple times. There is no way other than spells to decrease the monster's health.

Ibis wins when the health of the monster becomes 0 or below.

Find the minimum total Magic Points that have to be consumed before winning.

Constraints 1≤H≤10^4

1≤N≤10^3

1≤A i​≤10^4

1≤B i​≤10^4

All values in input are integers.

翻译

问题描述 伊比斯正在与一只怪兽战斗。

怪兽的生命值为 H。

伊比斯可以释放 N 种咒语。释放第 i 种咒语会使怪兽的生命值减少 A i,代价是 B i 魔法点数。

同一种咒语可以释放多次。除了咒语以外,没有其他方法可以减少怪兽的生命值。

当怪兽的生命值变为 0 或以下时,伊比斯获胜。

找出在获胜之前必须消耗的最小总魔法点数。

约束条件 1≤H≤10^4

1≤N≤10^3

1≤A i ≤10^4

1≤B i ≤10^4

输入中的所有值均为整数。

官方题解

通过考虑以下的动态规划问题可以解决这个问题。 DP[i] = 消耗的最小魔力值,以减少怪物的生命

值 i 由于可以多次使用相同的魔法,因此在更新 DP 数组时需要注意顺序。答案为 min

H≤i<H+max Ai DP[i] (为了减少怪物的生命值至少为 H + max Ai,需要先减少至少为 H,然后再

使用魔法是没有意义的)。这部分可以通过一种称为“提前汇总状态以持有 DP 数组”的实现技巧来

简化。时间复杂度为 O(NH)。 值得注意的是,答案最多达到 H * max Ai,因此,以下类型的 DP

无法解决这个问题。 DP[i] = 在消耗 i 魔力时可以减少的怪物生命值的最大值。

题解(ChatGPT)

完全背包问题是一个经典的动态规划问题,可以用动态规划来解决。在这个问题中,我们需要找到消灭怪兽所需的最小总魔法点数。

首先,我们定义一个二维数组 dp,其中 dp[i][j] 表示使用前 i 种法术时,消灭怪兽使其生命值为 j 时所需的最小总魔法点数。初始时,将 dp[0][0] 初始化为0,其余初始化为一个较大的数。

接下来,我们使用动态规划的思想进行状态转移。对于每种法术 i,我们可以选择使用0次、1次、2次...直至使用尽所有可能的次数。具体的状态转移方程如下:

dp[i][j] = min(dp[i-1][j], dp[i][j-A[i]] + B[i], dp[i][j-2*A[i]] + 2*B[i], ..., dp[i][j-k*A[i]] + k*B[i])

最终答案即为 dp[N][H]

下面是对应的C++代码:

#include <iostream>
#include <vector>
#include <climits>
using namespace std;

int main() {
    int H, N;
    cin >> H >> N;

    vector<int> A(N), B(N);
    for (int i = 0; i < N; i++) {
        cin >> A[i] >> B[i];
    }

    vector<vector<int>> dp(N + 1, vector<int>(H + 1, INT_MAX));
    dp[0][0] = 0;

    for (int i = 1; i <= N; i++) {
        for (int j = 0; j <= H; j++) {
            dp[i][j] = dp[i-1][j];
            for (int k = 1; k * A[i-1] <= j; k++) {
                if (dp[i-1][j-k*A[i-1]] != INT_MAX) {
                    dp[i][j] = min(dp[i][j], dp[i-1][j-k*A[i-1]] + k*B[i-1]);
                }
            }
        }
    }

    cout << dp[N][H] << endl;

    return 0;
}

补充题解(ChatGPT)

当解决这个问题时,我们使用了动态规划的思想。动态规划通常用于解决具有重叠子问题和最优子结构性质的问题。在这个问题中,我们可以将问题拆分为更小的子问题:消灭怪兽使其生命值为 j 时所需的最小总魔法点数。

我们使用二维数组 dp 来存储这些子问题的解,其中 dp[i][j] 表示使用前 i 种法术时,消灭怪兽使其生命值为 j 时所需的最小总魔法点数。初始时,我们将 dp[0][0] 初始化为0,表示使用0种法术消灭怪兽生命值为0时所需的魔法点数为0。

然后,我们使用动态规划的思想进行状态转移。对于每一种法术 i,我们可以选择使用0次、1次、2次...直至使用尽所有可能的次数。我们通过遍历 k 来尝试不同的使用次数,更新 dp[i][j] 的值。具体地,我们比较使用 k 次第 i 种法术和使用 k-1 次第 i 种法术的魔法点数消耗,选择其中较小的一个。

最终,当我们遍历完所有的法术种类和怪兽生命值后,dp[N][H] 中存储的就是消灭怪兽所需的最小总魔法点数。

这种动态规划的解法能够高效地解决问题,并且可以处理不同种类法术的情况。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值