背包

动态规划:

## 动态规划原理

  • 基本思想:问题的最优解如果可以由子问题的最优解推导得到,则可以先求解子问题的最优解,在构造原问题的最优解;若子问题有较多的重复出现,则可以自底向上从最终子问题向原问题逐步求解。
  • 使用条件:可分为多个相关子问题,子问题的解被重复使用
    • Optimal substructure(优化子结构):
      • 一个问题的优化解包含了子问题的优化解
      • 缩小子问题集合,只需那些优化问题中包含的子问题,降低实现复杂性
      • 我们可以自下而上的
    • Subteties(重叠子问题):在问题的求解过程中,很多子问题的解将被多次使用。
  • 动态规划算法的设计步骤:
    • 分析优化解的结构
    • 递归地定义最优解的代价
    • 自底向上地计算优化解的代价保存之,并获取构造最优解的信息
    • 根据构造最优解的信息构造优化解
  • 动态规划特点:
    • 把原始问题划分成一系列子问题;
    • 求解每个子问题仅一次,并将其结果保存在一个表中,以后用到时直接存取,不重复计算,节省计算时间
    • 自底向上地计算。
    • 整体问题最优解取决于子问题的最优解(状态转移方程)(将子问题称为状态,最终状态的求解归结为其他状态的求解)
01背包:有n种物品与承重为m的背包。每种物品只有一件,每个物品都有对应的重量weight[i]与价值value[i],求解如何装包使得价值最大。
dp(i,v)表示前i个物体(包括第i个)面对容量为v的背包的最大价值,c[i]代表物体i的重量,w[i]代表物体i的价值;如果第i个物体不放入背包,则背包的最大价值等于前i-1个物体面对容量v的最大价值;如果第i个物体选择放入,则背包的最大价值等于前i-1个物体面对容量v-cost[i]的最大价值加上物体i的价值w[i]。
对于实现,一般采用一个二维数组(状态转移矩阵)dp[i][j]来记录各个子问题的最优状态,其中dp[i][j]表示前i个物体面对容量j背包的最大价值。
下面给出0-1背包的基本实现,时间复杂度为O(N*V),空间复杂度也为O(N*V)
#include<iostream>
#include<stdio.h>
using namespace std;
const int maxn = 1e3+5;
int dp[maxn][maxn];
int weight[maxn];
int value[maxn];
int main(){
    int n,m;
    cin>>n>>m;
    memset(dp,0,sizeof(dp));
    for(int i = 1;i<=n;i++){
        scanf("%d%d",&w[i],&v[i]);
    }
    for(int i=1;i<=n;i++){
        for(int j=0;j<=m;j++){
            if(j<w[i]){
                dp[i][j] = dp[i-1][j];
            }
            else
                dp[i][j] = max(dp[i-1][j],dp[i-1][j-w[i]]+v[i]); 
        }
    }
    cout<<dp[n][m]<<endl;
    return 0;
}

 /*
1489.特大背包问题 (20分)
C时间限制:1000 毫秒 |  C内存限制:10000 Kb
题目内容:
现在有一个容量为C的背包和N个重量和价值已知的物品. 现在要从这n个物品中挑选出一些物品, 使得选择的物品的总重量不超过背包的容量, 且总价值最大.
此题的数据范围:
1 <= C <= 10^8(10的8次方)
1 <= N <= 100
输入描述
有多组测试数据. 第一行一个正整数T(T<=15), 表示测试数据组数.
对于每组测试数据:
第一行两个正整数N和C, 分别表示物品的数量和背包的容量.
接下来N行, 每行两个正整数w,v ,分别表示对应物品的重量和价值(1<= w <= 10^7, 1<= v <= 100)

输出描述
输出一个正整数, 表示在所选物品不超过背包容量的情况下, 能够得到的最大价值.

输入样例
1
3 10
5 10
5 10
4 12

输出样例
22*/

#include<iostream>
#include<stdio.h>
#include<string.h>
using namespace std;
typedef long long ll;
const int maxn = 1e2;
const int INF = 0x3f3f3f3f;
ll dp[maxn+1][maxn*maxn+1];
int n;
ll c;
ll w[maxn],v[maxn];
int main(){
    int t;
    cin>>t;
    while(t--){
        scanf("%d%lld",&n,&c);
        int m = 0;
        for(int i=0;i<n;i++){
            scanf("%lld%lld",&w[i],&v[i]);
        }
        fill(dp[0],dp[0]+maxn*maxn+1,INF);
        dp[0][0]=0;
        for(int i=0;i<n;i++){
            for(int j = 0;j<=maxn*maxn;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 res = 0;
        for(int i=0;i<=maxn*maxn;i++){
            if(dp[n][i]<=c){
                res = i;
            }
        }
        cout<<res<<endl;
        
        
    }
    return 0;
}
原文地址:https://www.cnblogs.com/lusiqi/p/11628684.html