背包
动态规划:
## 动态规划原理
- 基本思想:问题的最优解如果可以由子问题的最优解推导得到,则可以先求解子问题的最优解,在构造原问题的最优解;若子问题有较多的重复出现,则可以自底向上从最终子问题向原问题逐步求解。
- 使用条件:可分为多个相关子问题,子问题的解被重复使用
- Optimal substructure(优化子结构):
- 一个问题的优化解包含了子问题的优化解
- 缩小子问题集合,只需那些优化问题中包含的子问题,降低实现复杂性
- 我们可以自下而上的
- Subteties(重叠子问题):在问题的求解过程中,很多子问题的解将被多次使用。
- Optimal substructure(优化子结构):
- 动态规划算法的设计步骤:
- 分析优化解的结构
- 递归地定义最优解的代价
- 自底向上地计算优化解的代价保存之,并获取构造最优解的信息
- 根据构造最优解的信息构造优化解
- 动态规划特点:
- 把原始问题划分成一系列子问题;
- 求解每个子问题仅一次,并将其结果保存在一个表中,以后用到时直接存取,不重复计算,节省计算时间
- 自底向上地计算。
- 整体问题最优解取决于子问题的最优解(状态转移方程)(将子问题称为状态,最终状态的求解归结为其他状态的求解)
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;
}