(基础)01背包问题

问题描述

有n个物品,它们有各自的体积ci和价值wi,现有给定容量的背包v,如何让背包里装入的物品具有最大的价值总和?

原理:

  动态规划与分治法类似,都是把大问题拆分成小问题,通过寻找大问题与小问题的递推关系,解决一个个小问题,最终达到解决原问题的效果。但不同的是,分治法在子问题和子子问题等上被重复计算了很多次,而动态规划则具有记忆性,通过填写表把所有已经解决的子问题答案纪录下来,在新问题里需要用到的子问题可以直接提取,避免了重复计算,从而节约了时间,所以在问题满足最优性原理之后,用动态规划解决问题的核心就在于填表,表填写完毕,最优解也就找到。

思路:

  i为遍历的每一个物品,j为遍历0到v的体积,如果可以装下,由于装下不一定使总和最大,则装下即为dp[i-1][j-c[i]]+w[i],不装为dp[i-1][j],取两者中较大者。j-c[i]表示为目前物品空出空间,剩下的空间的价值取 之前可用空间下的最大值。

    由此可以得出递推关系式:

    1) j<c(i)      dp(i,j)=dp(i-1,j)

    2) j>=c(i)     dp(i,j)=maxdp(i-1,j)dp(i-1,j-c(i))+w(i)

输入:

5 10

2 1

3 5

2 5

3 4 

4 3

输出:

9

 

#include <stdio.h>
#include <iostream>
#include <math.h>
#include <string.h>
#include <algorithm>
using namespace std;
const double PI=acos(-1.0);
const int inf=0x7fffffff;
int w[105],c[105];
int dp[105][1000];
int n,v,mx,sum; 

int main(){
    cin>>n>>v;
    for(int i=1;i<=n;i++){
        cin>>w[i]>>c[i];
    }
    for(int i=1;i<=n;i++){
        for(int j=0;j<=v;j++){
            if(j>=c[i]){
                dp[i][j]=max(dp[i-1][j-c[i]]+w[i],dp[i-1][j]);//结果取选改物品和不选改物品价值的最大值 
            }
            else{
                dp[i][j]=dp[i-1][j];                        //空间不够,结果为之前的最大值 
            }
        }
    }
    cout<<dp[n][v];
    return 0; 
}

 节约空间写法:

#include <cstdio>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <math.h>
using namespace std;
const int inf=0x7fffffff;
const long long mod=1e9+7;
const double PI=acos(-1);
int w[105],c[105];
int dp[105];
int main()
{    
    int n,v;
    cin>>n>>v;
    for(int i=0;i<n;i++){
        cin>>w[i]>>c[i];
    }
    for(int i=0;i<n;i++){
        for(int j=v;j>=c[i];j--){
            dp[j]=max(dp[j-c[i]]+w[i],dp[j]);
        }
    }
    cout<<dp[v];
    return 0;
}

 

posted @ 2020-02-26 22:52  Maxwell·  阅读(209)  评论(0编辑  收藏  举报