0-1背包问题zZ

问题描述:

有n件物品,每件物品的重量为w[i],其价值为v[i],现在有个容量为m的背包,如何选择物品使得转入背包物品的价值最大。

思路:

首先想到的肯定是枚举所有物品的排列组合,再从中找到价值最大的那个组合,时间复杂度O(n!)。同样可以通过选择是否需要某个物品来枚举出所有的排列组合,时间复杂度O(2^n)。这样的时间复杂度是完全不能接受的

采用动态规划的方法,时间复杂度只有O(nm),具体方法如下:

首先设置一个二维数组dp[][],令dp[i][j]表示前i个物品装进容量为j的背包能获得的最大价值,最后dp[n][m]的值就是问题的解

算法过程:

算法过程就是求解dp[n][m]的值的过程

①确定问题边界:显然当i = 0或j = 0时,dp[i][j] = 0,即dp[i][0] = 0;dp[0][j] = 0

②化解子问题:dp[i][j]表示前i个物品装进容量为j的背包能获得的最大价值

③状态转移方程:

   对于容量为j的背包,考虑第i件物品,可将情况分为是否放入第i件物品两中情况:

   1)如果不放入第i件物品,那么这个问题就转换为前i - 1个物品放入容量为j的背包的问题,即dp[i][j] = dp[i - 1][j]

   2)如果放入第i件物品,那么当前背包的容量就变成了j - w[i],并使价值总量增加n[i],那么问题就转换成将前i-1个物品放入容量为j - w[i]的背包问题,即dp[i][j] = dp[i - 1][j - w[i]] + v[i]。

  最终确定状态转移方程:dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - w[i]] + v[i])

实例:

题目描述:

    北大网络实验室经常有活动需要叫外卖,但是每次叫外卖的报销经费的总额最大为C元,有N种菜可以点,经过长时间的点菜,网络实验室对于每种菜i都有一个量化的评价分数(表示这个菜可口程度),为Vi,每种菜的价格为Pi, 问如何选择各种菜,使得在报销额度范围内能使点到的菜的总评价分数最大。     注意:由于需要营养多样化,每种菜只能点一次。

输入描述:

  输入的第一行有两个整数C(1<=C<=1000)和(1<=N<=100),C代表总共能报销的额度,N代表能点的菜数目。些下来的N行中,每行包括两个在1到100之间(包括1和100)的整数,分别标识菜的价格和菜的评价分数。

输出:

   输出只包括一行,这一行只包含一个整数,表示在报销额度范围内,所点的菜得到的最大评价分数

样例输入:

90 4
20 25
30 20
40 50
10 18

样例输出:

95

代码:

#include <iostream>
#include <stdio.h>

using namespace std;

int main(){
    int n, c;
    while(scanf("%d %d", &c, &n) != EOF){
        int w[n + 1];
        int v[n + 1];
        int dp[n + 1][c + 1];
        for(int i = 1; i <= n; i ++){
            scanf("%d %d", &w[i], &v[i]);
        }
        for(int i = 0; i <= n; i ++){
            for(int j = 0; j <= c; j ++){
                if(i == 0 || j == 0){
                    dp[i][j] = 0;
                    continue;
                }
                if(w[i] <= j){
                    dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - w[i]] + v[i]);
                }else{
                    dp[i][j] = dp[i - 1][j];
                }
            }
        }
        cout << dp[n][c] << endl;
    }
    return 0;
}

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值