>

2018.02.06(背包专卖店)

2018.02.06

背包专卖店系列

    今天我们学习了背包问题,浏览了一个规模宏大的背包专卖店。。。领略了许许多多的背包。

0 - 1 背 包;完 全 背 包;多 重 背 包;混 合 背 包;部 分 背 包;

二 维 费 用 背 包;分 组 背 包;有 依 赖 背 包;

1. 0-1背包

思路:设$f[i][v]$表示前$i$件物品,总重量不超过$v$的最优价值,则$f[i][v]=max(f[i-1][v-w[i]]+c[i],f[i-1][v])$;$f[n][m]$即是最优解。

核心代码:

  $O(n^2)$空间复杂度版

 1 #include <stdio.h>
 2 #include <math.h>
 3 #include <string.h>
 4 int w[101],c[101];
 5 int f[101][1001];
 6 int _Max(int x,int y){return x>y?x:y;}
 7 int main(){
 8     int n,m;
 9     int i,j,v;
10     scanf("%d%d",&m,&n);
11     for(i=1;i<=n;i++)
12         scanf("%d%d",&w[i],&c[i]);
13     for(i=1;i<=n;i++)
14         for(v=m;v>0;v--)
15             if(w[i]<=v) f[i][v]=_Max(f[i-1][v],f[i-1][v-w[i]]+c[i]);
16             else f[i][v]=f[i-1][v];
17     printf("%d\n",f[n][m]);
18     return 0;
19 }
View Code

  $O(n)$空间复杂度版

 1 #include <stdio.h>
 2 #include <math.h>
 3 #include <string.h>
 4 int m,n;
 5 int w[31],c[31];
 6 int f[2001];
 7 int main(){
 8     int i,j,v;
 9     scanf("%d%d",&m,&n);
10     for(i=1;i<=n;i++)
11         scanf("%d%d",&w[i],&c[i]);
12     for(i=1;i<=n;i++){
13         for(v=m;v>=w[i];v--)
14             if(f[v-w[i]]+c[i]>f[v])
15                 f[v]=f[v-w[i]]+c[i];
16     }
17     printf("%d",f[m]);
18     return 0;
19 }
View Code

状态:AC

2.完全背包

思路:设$f[i][v]$表示前$i$件物品,总重量不超过$v$的最优价值,则$f[i][v]=max(f[i][v-w[i]]+c[i],f[i-1][v])$;$f[n][m]$即为最优解。

核心代码:

  $O(n^2)$空间复杂度版

 1 #include <stdio.h>
 2 #include <math.h>
 3 #include <string.h>
 4 int m,n;
 5 int w[31],c[31];
 6 int f[31][201];
 7 int main(){
 8     int i,j,v;
 9     scanf("%d%d",&m,&n);
10     for(i=1;i<=n;i++)
11         scanf("%d%d",&w[i],&c[i]);
12     for(i=1;i<=n;i++){
13         for(v=1;v<=m;v++){
14             if(v<w[i])
15                 f[i][v]=f[i-1][v];
16             else if(f[i-1][v]>f[i][v-w[i]]+c[i])
17                 f[i][v]=f[i-1][v];
18             else f[i][v]=f[i][v-w[i]]+c[i];
19         }
20     }
21     printf("%d",f[n][m]);
22     return 0;
23 } 
View Code

  $O(n)$空间复杂度版

 1 #include <stdio.h>
 2 #include <math.h>
 3 #include <string.h>
 4 int m,n;
 5 int w[31],c[31];
 6 int f[2001];
 7 int main(){
 8     int i,j,v;
 9     scanf("%d%d",&m,&n);
10     for(i=1;i<=n;i++)
11         scanf("%d%d",&w[i],&c[i]);
12     for(i=1;i<=n;i++){
13         for(v=w[i];v<=m;v++)
14             if(f[v-w[i]]+c[i]>f[v])
15                 f[v]=f[v-w[i]]+c[i];
16     }
17     printf("%d",f[m]);
18     return 0;
19 }
View Code

状态:AC

3.多重背包

思路:和完全背包相类似,只是物品取的次数不是一次,也不是无限次,而是有限的$n[i]$次,所以只要把状态转移方程改成$f[i][v]=max{f[i][v-k*w[i]]+k*c[i]}(0<=k<=n[i])$;$f[n][m]$为最优解。

核心代码: 

 1 #include <stdio.h>
 2 #include <math.h>
 3 #include <string.h>
 4 int v[6002],w[6002],s[6002];
 5 int f[6002];
 6 int m,n;
 7 int _Max(int x,int y){return x>y?x:y;}
 8 int main(){
 9     int i,j;
10     scanf("%d%d",&n,&m);
11     for(i=1;i<=n;i++)
12         scanf("%d%d%d",&v[i],&w[i],&s[i]);
13     for(i=1;i<=n;i++){
14         for(j=m;j>=0;j--)
15             for(int k=0;k<=s[i];k++){
16                 if(j-k*v[i]<0)break;
17                 f[j]=_Max(f[j],f[j-k*v[i]]+k*w[i]);
18             }
19     }
20     printf("%d",f[m]);
21     return 0;
22 } 
View Code

状态:AC

4.混合背包

思路:把前三种背包问题都综合起来,(其中0-1背包和完全背包类似,所以可以合并起来)用一个$if$来判断该物品是属于哪一种问题,再处理即可。

核心代码:

 1 #include <stdio.h>
 2 #include <math.h>
 3 #include <string.h>
 4 int m,n;
 5 int w[31],c[31],p[31];
 6 int f[201];
 7 int _Max(int x,int y){return x>y?x:y;}
 8 int main(){
 9     int i,j,k,v;
10     scanf("%d%d",&m,&n);
11     for(i=1;i<=n;i++)
12         scanf("%d%d%d",&w[i],&c[i],&p[i]);
13     for(i=1;i<=n;i++){
14         if(p[i]==0){
15             for(j=w[i];j<=m;j++)
16                 f[j]=_Max(f[j],f[j-w[i]]+c[i]);
17         }
18         else {
19             for(j=1;j<=p[i];j++)
20                 for(k=m;k>=w[i];k--)
21                     f[k]=_Max(f[k],f[k-w[i]]+c[i]);
22         }
23     }
24     printf("%d",f[m]);
25     return 0;
26 }
View Code

状态:AC

5.二维费用背包

思路:费用加了一维,状态也只需加一维,设$f[i][v][u]$表示前$i$件物品付出两种代价分别为$u$和$v$时可获得的最大价值。状态转移方程:$f[i][v][u]=max{f[i-1][v][u],f[i-1][v-a[i]][u-b[i]]+c[i]}$

核心代码:

 1 #include <stdio.h> 
 2 #include <math.h>
 3 #include <string.h>
 4 int v,u,k;
 5 int a[1001],b[1001],c[1001];
 6 int f[101][101];
 7 int main(){
 8     int i,j;
 9     memset(f,127,sizeof(f));
10     f[0][0]=0;
11     scanf("%d%d%d",&v,&u,&k);
12     for(i=1;i<=k;i++)
13         scanf("%d%d%d",&a[i],&b[i],&c[i]); 
14     for(i=1;i<=k;i++)
15         for(j=v;j>=0;j--)
16             for(int l=u;l>=0;l--){
17                 int t1,t2;
18                 t1=j+a[i];
19                 t2=l+b[i];
20                 if(t1>v)t1=v;
21                 if(t2>u)t2=u;
22                 if(f[t1][t2]>f[j][l]+c[i])
23                     f[t1][t2]=f[j][l]+c[i];
24             }
25     printf("%d",f[v][u]);
26     return 0;
27 }
View Code

6.分组背包

思路:???未理解,状态转移方程:$f[k][v]=max{f[k-1][v],f[k-1][v-w[i]]+c[i]}$;$f[k][v]$表示前$k$组物品花费$v$费用所获得的最大价值。

核心代码:

 1 #include <stdio.h>
 2 #include <math.h>
 3 #include <string.h>
 4 int v,n,t;
 5 int w[31],c[31];
 6 int a[11][32],f[201];
 7 int main(){
 8     int i,j,k;
 9     scanf("%d%d%d",&v,&n,&t);
10     for(i=1;i<=n;i++){
11         int p;
12         scanf("%d%d%d",&w[i],&c[i],&p);
13         a[p][++a[p][0]]=i;
14     }
15     for(k=1;k<=t;k++)
16         for(j=v;j>=0;j--)
17             for(i=1;i<=a[k][0];i++)
18                 if(j>=w[a[k][i]]){
19                     int tmp=a[k][i];
20                     if(f[j]<f[j-w[tmp]]+c[tmp])
21                         f[j]=f[j-w[tmp]]+c[tmp];
22                 }
23     printf("%d",f[v]);
24     return 0;
25 }
View Code

 状态:AC

P.S. 袁老师课后的习题我今天没做,我回家以后一定补上

posted @ 2018-02-06 17:05  Leo_wey  阅读(194)  评论(0编辑  收藏  举报