zoukankan      html  css  js  c++  java
  • 完全背包

    完全背包

    有n种重量和价值分别为wi,vi的物品,从这些物品中挑选总重量不超过W的物品,求出挑选物品价值总和的最大值。在这里,每种物品可以挑选任意多件。

    限制条件:1<=n<=100,1<=wi,vi<=100,1<=W<=10000。 

    分析一下:dp[i+1][j]代表从前i种物品中挑选总重量不超过j时总价值的最大值。

    递推关系为:dp[0][j]=0;

          dp[i+1][j]=max{dp[i][j-k*w[i]]+k*v[i] | 0<=k}

    可以写出程序如下

     1 #include<iostream>
     2 #include<algorithm>
     3 #include<memory.h>
     4 using namespace std;
     5 const int max_n=101;
     6 int w[max_n+1];
     7 int v[max_n+1];
     8 int n,r,W;
     9 int main()
    10 {
    11     cin>>n;
    12     for(int i=0;i<n;i++)
    13     {
    14         cin>>w[i]>>v[i];
    15     }
    16     cin>>W;
    17     int dp[n+1][W+1];
    18     memset(dp,0,sizeof(dp));
    19     for(int i=0;i<n;i++)
    20     {
    21         for(int j=0;j<=W;j++)
    22         {
    23             for(int k=0;k*w[i]<=j;k++)
    24             {
    25                 dp[i+1][j]=max(dp[i+1][j],dp[i][j-k*w[i]]+k*v[i]);
    26             }
    27         }
    28     }
    29     cout<<dp[n][W]<<endl;
    30     return 0;
    31 }
    View Code

    关于k的循环最坏可能从0循环到W,所以这个算法的复杂度为O(nW*W)

    可以做变形:max{dp[i][j-k*w[i]]+k*v[i] | 0<=k}

         =max(dp[i][j],max{dp[i][j-k*w[i]]+k*v[i] | 1<=k})

           =max(dp[i][j],max{dp[i][(j-w[i])-k*w[i]]+k*v[i] | 0<=k}+v[i])

           =max(dp[i][j],dp[i+1][j-w[i]]+v[i])

    所以递推关系式

            dp[i+1][j]=max(dp[i][j],dp[i+1][j-w[i]]+v[i])

    我们和01背包的递推关系式比较一下

            dp[i+1][j]=max(dp[i][j],dp[i][j-w[i]]+v[i])

    复杂度降为O(nW)

    程序如下

     1 #include<iostream>
     2 #include<algorithm>
     3 #include<memory.h>
     4 using namespace std;
     5 const int max_n=101;
     6 int w[max_n+1];
     7 int v[max_n+1];
     8 int n,r,W;
     9 int main()
    10 {
    11     cin>>n;
    12     for(int i=0;i<n;i++)
    13     {
    14         cin>>w[i]>>v[i];
    15     }
    16     cin>>W;
    17     int dp[n+1][W+1];
    18     memset(dp,0,sizeof(dp));
    19     for(int i=0;i<n;i++)
    20     {
    21         for(int j=0;j<=W;j++)
    22         {
    23             if(j>=w[i])
    24             {
    25                 dp[i+1][j]=max(dp[i][j],dp[i+1][j-w[i]]+v[i]);
    26             }
    27             else
    28             {
    29                 dp[i+1][j]=dp[i][j];
    30             }
    31         }
    32     }
    33     cout<<dp[n][W]<<endl;
    34     return 0;
    35 }
    View Code

    也可以通过过重复利用一个数组来实现dp。这个比较不好理解一些。

    看01背包的情况

     1 #include<iostream>
     2 #include<algorithm>
     3 #include<memory.h>
     4 using namespace std;
     5 const int max_n=101;
     6 int w[max_n+1];
     7 int v[max_n+1];
     8 int n,r,W;
     9 int main()
    10 {
    11     cin>>n;
    12     for(int i=0;i<n;i++)
    13     {
    14         cin>>w[i]>>v[i];
    15     }
    16     cin>>W;
    17     int dp[W+1];
    18     memset(dp,0,sizeof(dp));
    19     for(int i=0;i<n;i++)
    20     {
    21         for(int j=W;j>=w[i];j--)
    22         {
    23             dp[j]=max(dp[j],dp[j-w[i]]+v[i]);
    24         }
    25     }
    26     cout<<dp[W]<<endl;
    27     return 0;
    28 }
    View Code

    看完全背包的情况

     1 #include<iostream>
     2 #include<algorithm>
     3 #include<memory.h>
     4 using namespace std;
     5 const int max_n=101;
     6 int w[max_n+1];
     7 int v[max_n+1];
     8 int n,r,W;
     9 int main()
    10 {
    11     cin>>n;
    12     for(int i=0;i<n;i++)
    13     {
    14         cin>>w[i]>>v[i];
    15     }
    16     cin>>W;
    17     int dp[W+1];
    18     memset(dp,0,sizeof(dp));
    19     for(int i=0;i<n;i++)
    20     {
    21         for(int j=w[i];j<=W;j++)
    22         {
    23             dp[j]=max(dp[j],dp[j-w[i]]+v[i]);
    24         }
    25     }
    26     cout<<dp[W]<<endl;
    27     return 0;
    28 }
    View Code

    两者的差异只有循环的方向

  • 相关阅读:
    Android学习笔记ActionView
    Android学习笔记添加ActionItem
    Android学习笔记显示和隐藏ActionBar
    Android学习笔记上下文菜单
    Android学习笔记菜单资源文件
    Android学习笔记样式资源文件
    Android学习笔记主题(Theme)资源文件
    Android学习笔记StateListDrawable文件
    Android学习笔记.9.png格式图片
    笔记本外接显示器设置全屏壁纸
  • 原文地址:https://www.cnblogs.com/wangkaipeng/p/6429513.html
Copyright © 2011-2022 走看看