背包专题
01背包
hdu 2602
#include <bits/stdc++.h> using namespace std; #define N 1010 #define ll long long #define inf 0x3f3f3f3f int t; int n,V; struct Node{ int w,v; }no[N]; int dp[N]; int main() { scanf("%d",&t); while(t--){ fill(dp,dp+N,0);//初始化为0 scanf("%d%d",&n,&V); for(int i =0;i<n;i++) scanf("%d",&no[i].w); for(int i =0;i<n;i++) scanf("%d",&no[i].v); for(int i =0;i<n;i++){ for(int j =V;j>=no[i].v;j--) {//逆序,因为顺序某个可能被用多次。 dp[j] = max(dp[j],dp[j-no[i].v]+no[i].w);//不一定装满 } } printf("%d\n",dp[V]); } return 0; }
01背包+路径记录
public static Set<Integer> f(int w[], int val[]) { int n = w.length; int dp[] = new int[21]; int f[][] = new int[21][21]; List<Integer> list = new ArrayList<>(); for (int i = 0; i < n; i++) { for (int j = 20; j >= w[i]; j--) { if (dp[j] < dp[j - w[i]] + val[i]) { dp[j] = dp[j - w[i]] + val[i]; f[i][j] = 1; } } } int j = 20; Set<Integer> set = new HashSet<>(); for (int i = n - 1; i >= 0; i--) { if (f[i][j] == 1) { set.add(i); j -= w[i]; } } return set; }
多重背包
hdu 1171
1 #include <bits/stdc++.h> 2 using namespace std; 3 #define N 300010 4 #define ll long long 5 #define inf 0x3f3f3f3f 6 int t; 7 int n,V; 8 struct Node{ 9 int w,v; 10 }no[120]; 11 int dp[N],W[5100]; 12 int k,ans,sum; 13 int main() 14 { 15 16 while(~scanf("%d",&n)&&n>0) 17 { 18 ans =0; sum =0; 19 for(int i =0;i<n;i++){ 20 scanf("%d%d",&no[i].w,&no[i].v); 21 sum+=no[i].w*no[i].v; 22 k =1; 23 while(k<no[i].v){ 24 W[ans++] = k*no[i].w; 25 no[i].v-=k; 26 k<<=1; 27 } 28 W[ans++] = no[i].v*no[i].w; 29 } 30 //多重背包转化为01背包 31 fill(dp,dp+N,0);//初始化为0 32 for(int i =0;i<ans;i++){ 33 for(int j =sum/2;j>=W[i];j--){ 34 dp[j] = max(dp[j],dp[j-W[i]]+W[i]); 35 } 36 } 37 printf("%d %d\n",sum-dp[sum/2],dp[sum/2]); 38 } 39 return 0; 40 }
完全背包 每个可以取多次
hdu 1114
#include <bits/stdc++.h> using namespace std; #define N 10110 #define ll long long #define inf 0x3f3f3f3f struct Node{ int w,v; }no[520]; int dp[N]; int t,n,m,p; int main() { scanf("%d",&t); while(t--) { scanf("%d%d",&n,&m); m-=n; scanf("%d",&p); for(int i=0;i<p;i++){ scanf("%d%d",&no[i].w,&no[i].v); } fill(dp,dp+N,inf); dp[0] = 0; //要装满 for(int i =0;i<p;i++){ for(int j =no[i].v;j<=m;j++){//完全背包 dp[j]=min(dp[j],dp[j-no[i].v]+no[i].w); } } if(dp[m]!=inf){ printf("The minimum amount of money in the piggy-bank is %d.\n",dp[m]); } else{ printf("This is impossible.\n"); } } return 0; }
恰好装满问题
是否恰好装满的解法不同只在于初始值的不同
恰好装满:
求最大值时,除了dp[0] 为0,其他都初始化为无穷小 -0x3f3f3f3f
求最小值时,除了dp[0] 为0,其他都初始化为无穷大 0x3f3f3f3f
不必恰好装满: 全初始化为0