啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊我dp菜死了快来补一下。基本没讲解,来就放代码,偶尔写两句,也是在瞎扯。
简介
动态规划(dynamic programming)是运筹学的一个分支,是求解决策过程(decision process)最优化的数学方法。20世纪50年代初美国数学家R.E.Bellman等人在研究多阶段决策过程(multistep decision process)的优化问题时,提出了著名的最优化原理(principle of optimality),把多阶段过程转化为一系列单阶段问题,利用各阶段之间的关系,逐个求解,创立了解决这类过程优化问题的新方法——动态规划。
背包问题
背包是一类经典dp。
01背包
有N件物品和一个容量为V的背包。第i件物品的费用是c[i],价值是w[i]。求解将哪些物品装入背包可使价值总和最大。
关于初始化:
如果要求了把背包放满,那么初始化f[0]=0,f[1~n]=+INF。
如果没有要求放满,初始化为0。
所有的背包问题基本都这样初始化。
我们把j从m循环到w[i]:
1.寻找放了w[i]后剩余空间的最大值。
2.从大到小循环,保证当前状态的上一个状态不会出现已有当前物品的情况。
#include<cstdio> #include<algorithm> using namespace std; int n,m,w[205],c[205],f[205]; int main() { scanf("%d%d",&m,&n); for(int i=1;i<=n;i++) scanf("%d%d",&w[i],&c[i]); for(int i=1;i<=n;i++) for(int j=m;j>=w[i];j--) f[j]=max(f[j],f[j-w[i]]+c[i]); printf("%d\n",f[m]); return 0; }
完全背包
有N种物品和一个容量为V的背包,每种物品都有无限件可用。第i种物品的费用是c[i],价值是w[i]。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。
和0~1背包的唯一区别就是有可能一个物品放多种。
反正是同样的背包,你换一换第二维循环顺序不就行了吗?这样其实就是从绝不可能重复到可能重复,刚好满足完全背包的要求,理解清了0/1的循环顺序,这个也就没问题了。
#include<cstdio> #include<algorithm> using namespace std; int n,m,w[205],c[205],f[205]; int main() { scanf("%d%d",&m,&n); for(int i=1;i<=n;i++) scanf("%d%d",&w[i],&c[i]); for(int i=1;i<=n;i++) for(int j=w[i];j<=m;j++) f[j]=max(f[j],f[j-w[i]]+c[i]); printf("max=%d\n",f[m]); return 0; }
多重背包
有N种物品和一个容量为V的背包。第i种物品最多有n[i]件可用,每件费用是c[i],价值是w[i]。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。
这个题可以用二进制拆分思想来做,把每一个n[i]的系数化为1,2,4,...,2^(k-1),n[i]-2^k+1。
假如有一个n[i]=13,那么13=(2^0)+(2^1)+(2^2)+13-(2^3)+1,k在此处为3。
这样可以保证0~n[i]区间的每一个整数都可以用这些系数相加得到。
所以该问题能转化为0/1背包。
注意处理n-(2^k)+1。
多重背包复杂度O(vΣNi=1logn[i])
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; int n,type,m,v,wt,num; int T; struct node { int w=0,c=0; }; int f[1005]; int main() { scanf("%d",&T); while(T--) { n=0; node a[1005]; scanf("%d%d",&m,&type); while(type--) { scanf("%d%d%d",&v,&wt,&num); int p=1; while(num-p>0) { num-=p; a[++n].w=v*p; a[n].c=wt*p; p<<=1; } a[++n].w=num*v; a[n].c=wt*num; //注意要处理n[i]-(2^k)+1这个情况 } memset(f,0,sizeof(f)); for(int i=1;i<=n;i++) for(int j=m;j>=a[i].w;j--) f[j]=max(f[j],f[j-a[i].w]+a[i].c); printf("%d\n",f[m]); } return 0; }