hdu1059(多重背包优化)

使用一种二进制的优化, 可以完美的解决这题,《背包九讲》中说的非常好

但是还有一种线性复杂的算法。 应该算是该题很巧妙的解法

for(i=1;i<=6;i++)  
        {  
            for(l=total;l>=0;l--)  
            {  
                if(dp[l]==0)    continue;  
                for(k=1;k<=num[i]&&k*i+l<=total;k++)    
                {  
                    if(dp[k*i+l])   break;  // 这个剪枝瞬间将复杂度从N^2变成了N。 
                    dp[k*i+l]=1;  
                }  
            }  
        }  

代码中total是我们要装满的容量, 循环的次序很重要。 当关键还是那一步剪枝

 

在附上一份用二进制优化多重背包的代码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>
#include <math.h>
#include <map>
#include <queue>
#include <sstream>
#include <iostream>
using namespace std;
#define INF 0x3fffffff
struct node
{
    int w,c;
}g[10010]; //将log2压缩后的元素存在这里!

int k[10];
int dp[2002000];

int mpow(int x)
{
    int sum=1;
    for(int i=0;i<x;i++)
        sum=sum*2;
    return sum;
}

int main()
{
    //freopen("//home//chen//Desktop//ACM//in.text","r",stdin);
    //freopen("//home//chen//Desktop//ACM//out.text","w",stdout);
    int tt=1;
    while(1)
    {
        int tmp=0,sum=0;
        for(int i=1;i<=6;i++)
        {
            scanf("%d",&k[i]);
            tmp+=k[i];
            sum+=k[i]*i;
        }
        if(tmp==0) break;
        printf("Collection #%d:\n",tt++);
        if(sum%2!=0)
        {
            printf("Can't be divided.\n");
            printf("\n");
            continue;
        }
        int cnt=0;
        for(int i=1;i<=6;i++)
        {
            if(k[i]==0) continue;
            tmp=0;
            int tk=1;
            while(2*tk-1 < k[i])
            {
                g[cnt].w=1;
                g[cnt].c=i*tk;
                cnt++;
                tmp+=tk;
                tk*=2;
            }
            g[cnt].w=1;
            g[cnt].c=i*(k[i]-tmp);
            cnt++;
        }
        for(int i=1;i<=sum/2;i++)
        {
            dp[i]=-INF;
        }
        dp[0]=0;
        for(int i=0;i<cnt;i++)
        {
            for(int j=sum/2;j>=g[i].c;j--)
            {
                dp[j]=max(dp[j],dp[j-g[i].c]+g[i].w);
            }
        }
        if(dp[sum/2]>=0)
            printf("Can be divided.\n");
        else printf("Can't be divided.\n");
        printf("\n");
    }
    return 0;
}

 

posted @ 2013-07-02 13:46  chenhuan001  阅读(335)  评论(0编辑  收藏  举报