Piggy-Bank HDU - 1114 (完全背包) 由完全背包问题谈动态规划

150 阅读1分钟

 完全背包问题是一个很经典的动态规划问题

有n中价值和重量分别为wi, vi的物品, 从中选任意数量总重量不超过m的物品, 使得总价值最大, 每种物品可以挑任意次

直观思考的话, 由01背包问题来思考, 引入一个遍历k, 可得到以下状态转移方程

dp[i][j] = max{dp[i-1][j-w[i]k] + kv[i] | j >= w[i]*k }  (0 <= k < n)

int solve()
{
    ms(dp, 0);
    for(int i = 1; i <= n; i++)
        for(int j = 1; j <= m; j++){
            for(int k = 0; j >= k*w[i]; k++)
                dp[i][j] = max(dp[i][j],dp[i-1][j-k*w[i]]+k*v[i]);
        }
    return dp[n][m];
}

但复杂度太高了, 我们仔细思考, 其实存在了大量的重复计算, 可简化为以下

int solve()
{
    ms(dp, 0);
    for(int i = 1; i <= n; i++)
        for(int j = 1; j <= m; j++){
            if(j < w[i])
                dp[i][j] = dp[i-1][j];
            else
                dp[i][j] = max(dp[i-1][j], dp[i][j-w[i]]+v[i]); //避免重复计算
        }
    return dp[n][m];
}

如果题目对空间复杂度有要求的话, 还可以优化一下空间复杂度~

int solve()
{
    ms(dp, 0);
    for(int i = 1; i <= n; i++)
        for(int j = 1; j <= m; j++){
            if(j >= w[i])
                dp[j] = max(dp[j], dp[j-w[i]]+v[i]);
        }
    return dp[m];
}

下面来说这道题, 其实就是一个标准的完全背包问题, 只不过由取最大变成了取最小, max改成min就好了, 注意把边界设置为无穷大, 然后再判断一下是否有解即可

//完全背包问题
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
#include <vector>
#include <queue>
#include <cmath>
using namespace std;
#define ms(x, n) memset(x,n,sizeof(x));
typedef  long long LL;
const LL maxm = 10010, maxn = 510;
int n, m, v[maxn], w[maxn];
int dp[maxm];
void solve()
{
    for(int i = 0; i < maxm; i++)
        dp[i] = 1<<30;
    dp[0] = 0;
    for(int i = 1; i <= n; i++)
        for(int j = w[i]; j <= m; j++)
            dp[j] = min(dp[j], dp[j-w[i]]+v[i]);

    if(dp[m] != (1<<30))
        printf("The minimum amount of money in the piggy-bank is %d.\n",dp[m]);
    else
        printf("This is impossible.\n");
}

int main()
{
    int T, e, f;
    cin >> T;
    while(T--){
        cin >> e >> f;
        m = f-e; //背包的容量
        cin >> n;
        for(int i = 1; i <= n; i++)
            cin >> v[i] >> w[i];
        solve();
    }
    return 0;
}

\