• 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
    ",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. 袁老师课后的习题我今天没做,我回家以后一定补上

  • 相关阅读:
    Idea安装Mevn
    Spring_AOP
    Java_AOP原理
    Spring_数据校验和自定义检验规则和分组校验
    spring全局异常处理
    拦截器和自定义注解@interface
    linux下开启、关闭、重启mysql服务命令
    springboot的HelloWorld~~~
    切面自动装配注意点
    oracle分页
  • 原文地址:https://www.cnblogs.com/yzyl-Leo-wey/p/8423157.html
Copyright © 2020-2023  润新知