你的背包_多重!

来源:互联网 发布:matlab数据挖掘教程 编辑:程序博客网 时间:2024/05/15 21:03

P01:01背包问题

       有N种物品和一个容量为V的背包。第i种物品的费用是c[i],价值是w[i]。求解将哪些物品装入背包可使这些物品的费用总和不超过背包的容量,且价值总和最大。每种物品仅有一件。
P02:完全背包问题
       有N种物品和一个容量为V的背包。第i种物品的费用是c[i],价值是w[i]。求解将哪些物品装入背包可使这些物品的费用总和不超过背包的容量,且价值总和最大。每种物品都有无限件。
P03:多重背包问题
       有N种物品和一个容量为V的背包。第i种物品的费用是c[i],价值是w[i]。求解将哪些物品装入背包可使这些物品的费用总和不超过背包的容量,且价值总和最大。每种物品最多有n[i]件。

        P03:

        多重背包与完全背包类似。基本的算法只需要修改完全背包的方程即可。多重背包中,对于第i种物品有n[i]+1种策略,取0件,取1件,···,取n[i]件。同样定义dp[i][j],则可得出状态转移方程:

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

复杂度为O(V*∑n[i])。

 /****author :Or_me **╭︿︿︿╮{/ A  C /}  ( (OO) )   ︶︶︶ **    ****HDU_2191题**** 2014 年 7月 30日****/#include <cmath>#include <queue>#include <stack>#include <vector>#include <cstdio>#include <string>#include <cctype>#include <climits>#include <cstring>#include <cstdlib>#include <iostream>#include <algorithm>using namespace std;int p[500],h[500],c[500],dp[500];int main(){    int C;    scanf("%d",&C);    while (C--)    {        int n,m;        scanf("%d%d",&n,&m);        for (int i=0;i<m;i++)            scanf("%d%d%d",&p[i],&h[i],&c[i]);//价格,重量,袋数        memset(dp,0,500*4);        for (int i=0;i<m;i++)            for (int k=1;k<=c[i];k++)                for (int j=n;j>=p[i];j--)                     dp[j]=max(dp[j],dp[j-p[i]]+h[i]);        printf("%d\n",dp[n]);    }    return 0;}
       然后就是优化问题,考虑二进制的思想。考虑把第i种物品换成若干件物品,使得原问题中第i种物品可取的每种策略,取0件,取1件,···取n[i]件,均能等价于取若干件代换后的物品,而且取超过n[i]件的策略不会出现。

       将第i种物品分成若干件物品,其中每件物品有一个系数,这件物品的费用和价值均是原来的费用和价值乘以这个系数。使这些系数分别为1,2,4,···,2^(k-1),n[i]-2^k+1,且k是满足n[i]-2^k+1>0的最大整数。例,当n[i]=13时,k=3,所以就将这种物品分成系数分别为1,2,4,6的四件物品。

       分成的这几件物品的系数和为n[i],这就表明不可能取多于n[i]件的第i种物品。另外,这种方法也能保证对于0...n[i]间的每一个整数,均可以用若干个系数的和来表示,这个证明可以分0...2^(k-1)和2^k...n[i]两端来分别讨论。这样就将第i种物品分成了O(log(n[i]))种物品,将复杂度优化到O(V*∑long(n[i]))的01背包问题。

 /****author :Or_me **╭︿︿︿╮{/ A  C /}  ( (OO) )   ︶︶︶ **    ****HDU_2191题**** 2014 年 7月 30日****/#include <cmath>#include <queue>#include <stack>#include <vector>#include <cstdio>#include <string>#include <cctype>#include <climits>#include <cstring>#include <cstdlib>#include <iostream>#include <algorithm>using namespace std;int p[500],h[500],c[500],dp[500];void ZeroPack(int x,int y,int v)//价值、花费、容量{for (int i=v;i>=y;i--){dp[i]=max(dp[i],dp[i-y]+x);}}void CompletePack(int x,int y,int v)//价值、花费、容量{for (int i=y;i<=v;i++){dp[i]=max(dp[i],dp[i-y]+x);}}int main(){    int T;    scanf("%d",&T);    while (T--)    {    int n,m;    scanf("%d%d",&n,&m);    memset(dp,0,sizeof(dp));    for (int i=0;i<m;i++)    {    scanf("%d%d%d",&p[i],&h[i],&c[i]);//价格,重量,袋数    }    for (int i=0;i<m;i++)    {    if (c[i]*p[i]>=n)    {    CompletePack(h[i],p[i],n);    }    else    {    int k=1;    while (k<c[i])    {    ZeroPack(k*h[i],k*p[i],n);    c[i]-=k;    k*=2;    }    ZeroPack(c[i]*h[i],p[i]*c[i],n);    }    }    printf("%d\n",dp[n]);    }    return 0;}


0 0