完全背包问题

来源:互联网 发布:软件有实体么 编辑:程序博客网 时间:2024/05/29 16:11

Problem:

有n种重量分别为wi,vi 的物品。从这些物品中挑选出总重量不超过W的物品,求出挑选物品价值总和的最大值。在这里,每种物品可以挑选任意多件。

Input:

n=3

(w,v)={(3,4)(4,5)(2,3)}

w=7

Output:

10 (0号物品选1个,2号物品选2个)

Hint:

令d[i][j]:=从前 i 种物品中挑选总重量不超过 j 时总价值的最大值。

那么递推关系为:

dp[0][j] = 0

dp[i+1][j] = max(dp[i][j], dp[i+1][j-w[i]]+v[i])

代码如下:

#include<iostream>#include<fstream>#include<vector>#include<string>#include<map>#include<iterator>#include<algorithm>#include<numeric>#include<cmath>#include<sstream>#include<bitset>using namespace std;const int MaxN = 501;const int MaxW = 10001;int dp[MaxN][MaxW];vector<int> w;vector<int> v;int main(){#ifdef ONLINE_JUDGE#else    freopen("D:\\in.txt", "r", stdin);    freopen("D:\\out.txt", "w", stdout);#endif // ONLINE_JUDEG    int n(0);    int m(0);    memset(dp, 0, sizeof(dp));    scanf("%d%d", &n, &m);    int weight(0), value(0);    for (int i = 0; i < n; i++)    {        cin >> weight >> value;        w.push_back(weight);        v.push_back(value);    }    for (int i = 0; i <n; i++)    {        for (int j = 0; j <=m; j++)        {            if (j < w[i])            {                dp[i + 1][j] = dp[i][j];            }            else             {                dp[i + 1][j] = max(dp[i][j], dp[i+1][j - w[i]] + v[i]);            }        }    }    cout << dp[n][m] << endl;    return 0;}

此外,此前提到的01背包问题和这里的完全背包问题,可以通过不断重复利用一个数组来实现。

01背包问题的情况:

int dp[MaxW + 1];void solve(){    for (int i = 0; i<n; i++)        for (int j = m; j >= w[i]; j--)        {            //放入和不放入的情况都尝试一下,注意循环方向                        dp[j] = max(dp[j], dp[j - w[i]] + v[i]);        }    cout << dp[m] << endl;}

多重背包的情况:

int dp[MaxW + 1];void solve(){    for (int i = 0; i<n; i++)        for (int j = w[i]; j <=m; j++)        {            //放入和不放入的情况都尝试一下,注意循环方向                        dp[j] = max(dp[j], dp[j - w[i]] + v[i]);        }    cout << dp[m] << endl;}

像这样书写的话,两者的差异就变成只有循环的方向了。重复利用数组虽然可以节省内存空间,但使用不好的将有可能留下bug,所以要格外小心。不过出于节约内存的考虑,有时候必须要重复利用数组,也存在通过重复利用能够进一步降低复杂度的问题。


重复利用数组的解法如下:

#include<iostream>#include<fstream>#include<vector>#include<string>#include<map>#include<iterator>#include<algorithm>#include<numeric>#include<cmath>#include<sstream>#include<bitset>using namespace std;const int MaxN = 501;const int MaxW = 10001;int dp[MaxW + 1];vector<int> w;vector<int> v;int main(){#ifdef ONLINE_JUDGE#else    freopen("D:\\in.txt", "r", stdin);    freopen("D:\\out.txt", "w", stdout);#endif // ONLINE_JUDEG    int n(0);    int m(0);    memset(dp, 0, sizeof(dp));    scanf("%d%d", &n, &m);    int weight(0), value(0);    for (int i = 0; i < n; i++)    {        cin >> weight >> value;        w.push_back(weight);        v.push_back(value);    }    for (int i = 0; i <n; i++)    {        for (int j = w[i]; j <= m;j++)        {                dp[j] = max(dp[j], dp[j - w[i]] + v[i]);        }    }    cout << dp[m] << endl;    return 0;}


0 0
原创粉丝点击