01背包问题2

问题描述

有n个重量和价值分别为wi,vi的物品。从这些物品中挑选总重量不超过W的物品,求所有挑选方案中价值总和最大的方案

输入样例

4 5
2 1 3 2
3 2 4 2

输出样例

7

取值范围

1<=n<=100
1<=wi<=10^7
1<=vi<=100
1<=W<=10 ^9

分析:这里与背包问题1不同的地方是修改了限制的条件,求解这一问题的复杂度是O(NW),对于这一问题的规模来讲就不够用了,相比
较重量来说,价值的范围较小一些,所以可以改变DP的对象,背包问题1用DP来表示不同重量下的最大价值,这次我们不妨用DP来表示不同
价值下的最小重量。
定义:dp[i+1][j]表示前i个物品挑选出价值总和为j时的最小重量,(不存在是就是一个充分大的数INF)由于前0个物品都挑选不了
所以dp[0][0]=0, dp[0][j]=INF,状态转移式为:dp[i+1][j]=min(dp[i][j],dp[i][j-v[j]]+w[j])

代码如下:

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<iostream>
#define INF 1000000000
#define max_n 100
#define max_v 100
using namespace std;
int n,W;
int dp[max_n+5][max_n*max_v+5];
int w[max_n+5],v[max_n+5];
void solve()
{
    for(int i=0;i<n;i++){
        for(int j=0;j<=max_n*max_v+5;j++){
            if(j<v[i])dp[i+1][j]=dp[i][j];
            else dp[i+1][j]=min(dp[i][j],dp[i][j-v[i]]+w[i]);
        }
    }
}
int main()
{
    scanf("%d%d",&n,&W);
    for(int i=0;i<n;i++)
        scanf("%d",&w[i]);
    for(int i=0;i<n;i++)
        scanf("%d",&v[i]);
    fill(dp[0],dp[0]+max_n*max_v+5,INF);   //初始化
    dp[0][0]=0;
    solve();
    int res=0;
    for(int i=0;i<=max_n*max_v;i++){
        if(dp[n][i]<=W)res=i;
    }
    printf("%d\n",res);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_43328040/article/details/88077118