zoukankan      html  css  js  c++  java
  • 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. 袁老师课后的习题我今天没做,我回家以后一定补上

  • 相关阅读:
    hdu 1017 A Mathematical Curiosity 解题报告
    hdu 2069 Coin Change 解题报告
    hut 1574 组合问题 解题报告
    hdu 2111 Saving HDU 解题报
    hut 1054 Jesse's Code 解题报告
    hdu1131 Count the Trees解题报告
    hdu 2159 FATE 解题报告
    hdu 1879 继续畅通工程 解题报告
    oracle的系统和对象权限
    oracle 自定义函数 返回一个表类型
  • 原文地址:https://www.cnblogs.com/yzyl-Leo-wey/p/8423157.html
Copyright © 2011-2022 走看看