一、问题类型(状态的表示和状态的转移)
背包问题、线性dp、区间dp、状态压缩dp、树形dp、计数、数位统计、状态压缩、记忆化搜索。
二、背包问题
(一)0 1背包(每件物品最多只用一次)
N个物品,V个背包。每个物品v表示体积,w表示权重。背包能装下的情况下,求最大的总价值。
0.1背包dp的思考方式:
1、如何表示状态、如何计算:
如何表示状态:
2、状态就是一个满足条件的集合,集合是所有选法的集合(选哪些物品)。条件:只从前i个中选,总体积小于等于j。
3、状态的值f(i,j)就是集合的属性(max,min,数量)
4、答案是f(n,v);
如何进行状态计算:
1、状态计算是对集合的划分,对集合划分子集,以及如何经过划分后的子集进行计算得到结果
2、对集合f(i,j)进行划分:划分的依据就是子集是否包含i。一个是不包含i,一个是必须包含i
3、如何对划分的子集进行计算得到最后的结果:
4、对于必须含i的子集。如果要求最大值,可以先不去考虑i号,因为必须要选i号,所以先把i号物品刨除去,计算f(i-1,j-vi)+wi。
5、max(f(i-1 , j), f(i-1,j-vi)+wi)
01背包二维写法
#include<bits/stdc++.h>
using namespace std;
// 2 01背包 二维写法
const int N=1010;
int n,m;
int v[N],w[N];
int f[N][N];
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++)cin>>v[i]>>w[i];
//全不选的话价值就是0
for(int i=0;i<=m;i++)f[0][i]=0;
//循环的方式扩大集合依次求解
for(int i=1;i<=n;i++)
for(int j=0;j<=m;j++)
{
//注意这样存在的一个错误性:vi比背包还大
//f[i][j]=max(f[i-1][j],f[i-1][j-v[i]]+w[i]);
f[i][j]=f[i-1][j];
if(v[