01背包问题--C++

一、题目:

有 N件物品和一个容量是 V的背包。每件物品只能使用一次。

第 i件物品的体积是 vi,价值是 wi。

求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。
输出最大价值。

输入格式

第一行两个整数,N,V用空格隔开,分别表示物品数量和背包容积。

接下来有 N行,每行两个整数 vi,wi用空格隔开,分别表示第 i件物品的体积和价值。

输出格式

输出一个整数,表示最大价值。

数据范围

0<N,V≤10000<N,V≤1000
0<vi,wi≤10000<vi,wi≤1000

输入样例

4 5
1 2
2 4
3 4
4 5

输出样例:

8

 

二、思路: 

实际问题--数学--算法--实现的一个过程。

这是一道经典的动态规划题:

补充知识:什么是动态规划?其解题思路?基本技巧?:

1.问题抽象化?2.建立模型?3.寻找约束条件?4.判断是否满足最有性原理?5.找大问题与小问题的递推关系?6.填表7.寻找最优解?

首要问题:

1.什么是问题抽象化?

我理解能解决问题抽象化的工具或思维是数学:首先是数学知识:(离散,几何,代数,数值计算,概率,函数,变换,组合排序...)

让知识和问题对号入座,即找到对应的数学知识去初步建立解决实际问题的解。这道背包问题的数学知识比较简单,比如一个小于号的数学知识,装载最大物品体积要小于背包体积,很简单吧

2.什么是建立模型?:这个话题很大,概念很抽象,什么是建模?建模是什么?纠结这个问题很难有答案:这里例举数学建模中常用的已完成且能解决一类问题的建模模型,自行体会效果更好:类比法、二分法、差分法、变分法、图论法、层次分析法、数据拟合法、回归分析法、数学规划(线性规划,非线性规划,整数规划,动态规划,目标规划)、机理分析、排队方法、对策方法、决策方法、模糊评判方法、时间序列方法、灰色理论方法、现代优化算法(禁忌搜索算法,模拟退火算法,遗传算法,神经网络)。
就拿二分法来说,在排好序的序列中查找某个数,这里有什么数学知识?好像感觉不强,完全是一系列操作组合的感觉,二分法先是与中间值比较,比它大则往右半边范围寻找,与右半边的中间值比较,比它大又往右半边取中间值...不断进行,直到找到最优解。也就是说这一系列的操作组合成的一个过程也叫模型,也完成了建模。在这个过程中要体会的是,二分法操作的对象是排好序的数组,这个是算法建模的重点和难点,另外一系列的操作也是极其重要的,因为这一系列操作可以得出答案。

3.寻找最优解:

这个步骤需要注意的是怎样才能找到最优解,也就是说要经过怎样的一系列操作后可以得到最优解。01背包的一系列操作在于动态规划,即先构建状态矩阵V(N+1,N+1),也就是用到数学知识,分解为矩阵,接下来是构建状态方程V(i,j),i表示当前选择物品放入背包,j表示当前背包的容量,V(i,j)表示当前背包放入物品的总价值,但是第i个物品还没放;然后对这个状态方程进行状态转移,01背包的状态方程转移是描述状态转移过程的过程,if (j>=w(i) ) V(i,j)=max(V(i-1,j),V(i,j-w(i))+v(i));这里解释一下,V(i-1,j)表示前i-1个物品放入背包后的总价值,接下来,当放入第i个物品的时候,就是要么Wi>j,必然是放不进去了,所以V(i,j)=V(i-1,j),要么j>=w(i),共两种选择:放进去与不放,只要找到 最大值即V(i,j)=max{V(i-1,j),V(i-1,j-w(i))+v(i)}。那么根据这个关系递推就可以。这个状态矩阵的大小需要是int[N+1][V+1].默认j=0,以及i=0的时候状态是0。

原文:https://blog.csdn.net/lemaden520/article/details/77931930 

三、实现:C++

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 1005;
int w[MAXN];    // 重量 
int v[MAXN];    // 价值 
int f[MAXN][MAXN];  // f[i][j], j重量下前i个物品的最大价值 
int res=0;
int main() 
{
    int n, m;   
    cin >> n >> m;
    for(int i = 1; i <= n; ++i) //索引从1开始
        cin >> w[i] >> v[i];
    
    for(int i = 1; i <= n; ++i) 
        for(int j = 1; j<=m; ++j)
        {
            //  当前重量装不进,价值等于前i-1个物品
            if(j<w[i]) 
                f[i][j] = f[i-1][j];
            // 能装,需判断 
            else    
                f[i][j] = max(f[i-1][j], f[i-1][j-w[i]]+v[i]);
        } 

    cout<<f[n][m];
    return 0;
}

 

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值