• 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:
    ",tt++);
            if(sum%2!=0)
            {
                printf("Can't be divided.
    ");
                printf("
    ");
                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.
    ");
            else printf("Can't be divided.
    ");
            printf("
    ");
        }
        return 0;
    }
  • 相关阅读:
    《编程珠玑,字字珠玑》读书笔记完结篇——AVL树
    中国人,不能自卑,要自强于世界民族之林
    做饭方法
    创建一个强名称密钥文件+ 如何在 Visual C# .NET 中将程序集安装到全局程序集缓存中
    .Net 题目
    页面传值的另一种办法
    成功的12条黄金法则
    English学习资料大全
    .NET中的Serialization
    页面标签使用 实现定位
  • 原文地址:https://www.cnblogs.com/chenhuan001/p/3166816.html
Copyright © 2020-2023  润新知