完全背包问题

完全背包问题

1.1 题目描述

  • 有N中物品和一个容量为V的背包。每种物品都有无限件。第i种物品体积为w[i],价值是v[i]。要求放入背包中的物品价值总和是最大的。

1.2 基本思路

  • 这个问题和上篇讲过的01背包问题有点像,不同的是每件物品都有无限件。按照01背包的思路,每件物品就不再是取或者不取的状态,而是可以取多件。背包不是无限大,第i物品最多只能取V/w[i]件。用dp[i][j]来表示前面i件物品放入一个容量为j的背包中价值总和最大是多少。可以写出一个状态转移方程

\[dp[i][j] = max\{dp[i-1][j-k*w[i]] +k*v[i] |0=<k*w[i]<=V\} \]

题目连接

代码

#include<stdio.h>
#include<string.h>
int max(int a, int b)
{
    return a > b ?  a : b;
}
int dp[1005][1005];
int main()
{
    int N, V;
    int v[1005];
    int w[1005];

    memset(dp, 0, sizeof(dp));
    scanf("%d %d\n", &N, &V);
    for(int i = 1; i <= N; i++)
        scanf("%d %d", &w[i], &v[i]);
    for(int i = 1; i <= N; i++)
    {
        for(int j = 1; j <= V; j++)
        {
            for(int k = 0; k <= j/w[i]; k++)
            {
                if(j < w[i])    dp[i][j] = dp[i-1][j];
                else
                dp[i][j] = max(dp[i][j], dp[i-1][j - k * w[i]] + k * v[i]);
            }
        }
    }
    printf("%d\n", dp[N][V]);
    return 0;
    }

1.3 时间复杂度优化

  • 上述方法的时间复杂度为O(VNΣ W/v[i]),是比较大的。将上述状态转移方程进行优化

    \[dp[i][j] = max\{dp[i-1][j-k*w[i]]+k*v[i]|0<=k\}\\ dp[i][j] = max\{dp[i-1][j], max\{dp[i-1][j-k*w[i]] + k * v[i] | 1<=k\}\}\\ dp[i][j] = max\{dp[i-1][j], max\{dp[i-1][j-w[i]-k*w[i]] + k * v[i] + v[i] | 0<=k\}\}\\ dp[i][j] = max\{dp[i-1][j], max\{dp[i-1][j-w[i]-k*w[i]] + k * v[i]| 0<=k\}\}+v[i]\\ dp[i][j] = max\{dp[i-1][j], dp[i][j-w[i]]+v[i]\} \]

这样时间复杂度就从三次降到了两次

代码

#include<stdio.h>
#include<string.h>
int max(int a, int b)
{
    return a > b ?  a : b;
}
int dp[1005][1005];
int main()
{
    int N, V;
    int v[1005];
    int w[1005];

    memset(dp, 0, sizeof(dp));
    scanf("%d %d\n", &N, &V);
    for(int i = 1; i <= N; i++)
        scanf("%d %d", &w[i], &v[i]);
    for(int i = 1; i <= N; i++)
    {
        for(int j = 1; j <= V; 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]);
        }
    }
    printf("%d\n", dp[N][V]);
    return 0;
}

1.4 空间复杂度优化

dp[i][j]只依赖于dp[i-1][j]和dp[i][j-w[i]],可以用滚动数组优化空间

代码

#include<stdio.h>
#include<string.h>
int max(int a, int b)
{
    return a > b ?  a : b;
}
int dp[2][1005];
int main()
{
    int N, V;
    int v[1005];
    int w[1005];

    memset(dp, 0, sizeof(dp));
    scanf("%d %d\n", &N, &V);
    for(int i = 1; i <= N; i++)
        scanf("%d %d", &w[i], &v[i]);
    for(int i = 1; i <= N; i++)
    {
        for(int j = 1; j <= V; j++)
        {
            if(j < w[i])    dp[i%2][j] = dp[(i-1)%2][j];
            else            dp[i%2][j] = max(dp[(i-1)%2][j], dp[i%2][j-w[i]] + v[i]);
        }
    }
    printf("%d\n", dp[N%2][V]);
    return 0;
}

1.5 小结

做动态规划的题目,推出状态转移方程以及其中的意思是非常重要的

posted @ 2020-03-20 14:49  Bep  阅读(157)  评论(0)    收藏  举报