背包问题
思想或许可以看作:
实质是枚举所有的情况,来达到想要的目的,但是这个过程中,通过局部的最优解(线性的推导),来省略了很多种情况,从而减少时间复杂度。
应用:
- 遇到取数问题
- 和一些明显有背包影子的东西。
二进制多重背包问题:
仔细看代码
#include <bits/stdc++.h> using namespace std; #define ri register int #define M 10005 struct dian{ int val,v; }p[M]; int n,m; int dis[M]; int trmp; int main(){ scanf("%d%d",&n,&m); for(ri i=1;i<=n;i++) { int a,b,c; scanf("%d%d%d",&a,&b,&c); for(int j=1;j<=c;j<<=1) // { p[++cent].v=a*j; p[cent].val=b*j; c-=j; } if(c) p[++cent].v=c*a,p[cent].val=c*b; // 这个c作为分界点,前后都可以表示出来 } for(ri i=1;i<=cent;i++) for(ri j=m;j>=p[i].val;j++) { dis[j]=max(dis[j-p[i].v]+p[i].val,dis[v]); } printf("%d",dis[m]); }
分组背包的
就对与每一个 v 分组挑选一个最好的
#include <bits/stdc++.h> using namespace std; #define ri register int #define M 1005 vector <int> q[11]; struct dain{ int val,v; }p[M]; int n,m,T; int dis[M]; int mx(int v,int t) { int maxx=dis[v]; for(ri i=0;i<q[t].size();i++) { int b=q[t][i]; if(v-p[b].v>=0) { maxx=max(maxx,dis[v-p[b].v]+p[b].val); } } return maxx; } int main(){ scanf("%d%d%d",&m,&n,&T); for(ri i=1;i<=n;i++) { int t; scanf("%d%d%d",&p[i].v,&p[i].val,&t); q[t].push_back(i); } for(ri i=1;i<=T;i++) // for(ri j=m;j>=1;j--) { dis[j]=mx(j,i); } printf("%d",dis[m]); return 0; }
无限背包问题:
顺序 1--m
01背包问题
逆序m--1
需要回溯的背包:
- 二维
- 2个数组就行了
后记:
- 一定要确保j-w值>=0; 分组背包要进行特判,其他背包,直接在for(里面进行限制就行了)
- 更新的时候直接max,就行了,不用像最短路一样