【洛谷 P1510】精卫填海 题解(动态规划+01背包)

精卫填海

题目描述

本题为改编题。

发鸠之山,其上多柘木。有鸟焉,其状如乌,文首,白喙,赤足,名曰精卫,其名自詨。是炎帝之少女,名曰女娃。女娃游于东海,溺而不返,故为精卫。常衔西山之木石,以堙于东海。——《山海经》

精卫终于快把东海填平了!只剩下了最后的一小片区域了。同时,西山上的木石也已经不多了。精卫能把东海填平吗?

事实上,东海未填平的区域还需要至少体积为 v v v 的木石才可以填平,而西山上的木石还剩下 n n n 块,每块的体积和把它衔到东海需要的体力分别为 k k k m m m。精卫已经填海填了这么长时间了,她也很累了,她还剩下的体力为 c c c

输入格式

输入文件的第一行是三个整数: v , n , c v,n,c v,n,c

从第二行到第 n + 1 n+1 n+1 行分别为每块木石的体积和把它衔到东海需要的体力。

输出格式

输出文件只有一行,如果精卫能把东海填平,则输出她把东海填平后剩下的最大的体力,否则输出 Impossible(不带引号)。

样例 #1

样例输入 #1

100 2 10
50 5
50 5

样例输出 #1

0

样例 #2

样例输入 #2

10 2 1
50 5
10 2

样例输出 #2

Impossible

提示

数据范围及约定

  • 对于 20 % 20\% 20% 的数据, 0 < n ≤ 50 00<n50
  • 对于 50 % 50\% 50% 的数据, 0 < n ≤ 1000 00<n1000
  • 对于 100 % 100\% 100% 的数据, 0 < n ≤ 1 0 4 00<n104,所有读入的数均属于 [ 0 , 1 0 4 ] [0,10^4] [0,104],最后答案不大于 c c c

思路

状态转移方程:

dp[j] = max(dp[j], dp[j - m[i]] + k[i]);

dp[j] 表示当前体力值为 j 时,精卫所能携带的最大石头体积。对于每一块石头 i,从 c 到 m[i] 枚举体力值 j,并尝试将它放入背包中。如果将石头 i 放入背包中所能得到的总体积 dp[j-m[i]] 加上 k[i] 大于 dp[j],则更新 dp[j] 的值。最后,从 0 到 c 遍历 dp 数组,找到第一个 dp[j] 大于等于 v 的位置,输出 c-j 即为所需体力值。如果遍历结束后仍然没有找到符合条件的位置,则输出 Impossible。


AC代码

#include 
#include 
#define AUTHOR "HEX9CF"
using namespace std;

const int N = 1e4 + 5;

// 需要体积,总石头数,总体力
int v, n, c;
// 运送i块石头,j体力所能运送的最大体积
int dp[N];
// 每块体积,所需体力
int k[N], m[N];

int main()
{
    cin >> v >> n >> c;
    for (int i = 1; i <= n; i++)
    {
        cin >> k[i] >> m[i];
    }
    for (int i = 1; i <= n; i++)
    {
        for (int j = c; j >= m[i]; j--)
        {
            dp[j] = max(dp[j], dp[j - m[i]] + k[i]);
        }
    }
    for (int j = 0; j <= c; j++)
    {
        if (dp[j] >= v)
        {
            // 输出她把东海填平后剩下的最大的体力
            cout << c - j << endl;
            return 0;
        }
    }
    // cout << dp[n][c] << endl;
    cout << "Impossible" << endl;
    return 0;
}

你可能感兴趣的:(数据结构与算法,动态规划,算法,c++)