zoukankan      html  css  js  c++  java
  • 0-1背包问题

    【问题】

    有一个贼在偷窃一家商店时发现有N件物品;第i件物品值pi元,重wi磅(1≤i≤N),且都是整数。

    他希望带走的东西越值钱越好,但他的背包中最多能装下M磅的东西(整数)。

    如果每件物品或被带走或被留下,小偷应该带走哪几样东西?

    【算法解析】

    令f(i,y) 表示容量为y,物品i,i+1,···,n 的优化效益值,按优化原理可列递归关系如下:

    初始背包问题的递归方程
    f(1,c)=max{f(2,c), f(2,c-w1)+p1}
    迭代
    计算从f(n, *)开始((1)式)
    然后应用(2)式递归计算f(i,*) ( i=n-1,n-2,···,2 ),
    最后得出 f(1,c)

    【代码】

    (1)递归法:

    #include <iostream>
    
    using namespace std;
    
    const int n=3;
    int w[n]={100,14,10};
    int p[n]={20,18,15};
    
    int F(int i, int y)
    {
       if (i == n) return (y < w[n]) ? 0 : p[n];
       if (y < w[i]) return F(i+1,y);
       return max(F(i+1,y), F(i+1,y-w[i]) + p[i]);
    }
    
    int main() {
        cout<<F(0,116);
        return 0;
    }

    时间复杂度分析:

    程序的最坏时间复杂性t(n)
    t(1)=a;
    t(n)=2t(n-1)+b (n>1),其中a,b为常数
    求解可得t(n)=Θ(2^n)

    (2)迭代法:

    #include <iostream>
    
    using namespace std;
    
    //该算法用二维数组f [i][y]来保存各个 f 的值
    //二维数组需Θ((n+1)*(c+1))空间
    template<class T>
    void Knapsack(T p[], int w[], T** f, int c, int n)
    {
        //f(n,y)
        int yMax = min(w[n]-1,c);
        for (int y = 0; y <= yMax; y++)
          f[n][y] = 0;
        for (int y = w[n]; y <= c; y++)
          f[n][y] = p[n];
          
        // compute remaining f's
        for (int i = n - 1; i > 1; i--){
          yMax = min(w[i]-1,c);
          for (int y = 0; y <= yMax; y++)
             f[i][y] = f[i+1][y];
          for (int y = w[i]; y <= c; y++)
             f[i][y] = max(f[i+1][y],f[i+1][y-w[i]] + p[i]);
        }
        
        //i=1时单独处理!
        f[1][c] = f[2][c];
        if (c >= w[1])
          f[1][c] = max(f[1][c], f[2][c-w[1]] + p[1]);
    }
    
    //函数Traceback从f[i][y]产生优化的xi值
    //Traceback的复杂性为Θ(n).
    template<class T>
    void Traceback(T **f, int w[], int x[], int c, int n)
    { // Compute x for optimal filling.
       for (int i = 1; i < n; i++){
               if (f[i][c] == f[i+1][c])
               x[i] = 0;
            else {
                x[i] = 1;
                c -= w[i];
            }
       }
       
       x[n] = (f[n][c]) ? 1 : 0;
    }
    
    
    int main() {
        const int c=116;
        const int n=3;
        int w[n+1]={-1,100,14,10};
        int p[n+1]={-1,20,18,15};
        int **f=new int*[n+1];
        for(int i=0;i<=n;i++){
            f[i]=new int[c+1];
        }
        int x[n+1];
        
        Knapsack(p,w,f,c,n);
        Traceback(f,w,x,c,n);
        
        cout<<f[1][c]<<endl;
        for(int i=1;i<=n;i++){
            cout<<x[i]<<"	";
        }
        
        delete[]f;
        return 0;
    }

    上述程序有两个缺点:
    1)要求物品重量为整数;
    2)当背包容量c 很大时,例如c>2n,程序的复杂性为Ω(n2n).

  • 相关阅读:
    HTML+CSS+JS设计注册页面
    1.20学习总结
    Linux安装python3
    Linux命令
    vue安装
    Python实现发送邮件
    C语言带参数的main函数
    Fibonacci 数列递归 重复计算
    gray code 格雷码 递归
    河内塔
  • 原文地址:https://www.cnblogs.com/wxgblog/p/0-1beibaowenti.html
Copyright © 2011-2022 走看看