zoukankan      html  css  js  c++  java
  • HDU_1059 多重背包问题

    F - Dividing
    Time Limit:1000MS     Memory Limit:10000KB     64bit IO Format:%I64d & %I64u
    Submit Status

    Description

    Marsha and Bill own a collection of marbles. They want to split the collection among themselves so that both receive an equal share of the marbles. This would be easy if all the marbles had the same value, because then they could just split the collection in half. But unfortunately, some of the marbles are larger, or more beautiful than others. So, Marsha and Bill start by assigning a value, a natural number between one and six, to each marble. Now they want to divide the marbles so that each of them gets the same total value. Unfortunately, they realize that it might be impossible to divide the marbles in this way (even if the total value of all marbles is even). For example, if there are one marble of value 1, one of value 3 and two of value 4, then they cannot be split into sets of equal value. So, they ask you to write a program that checks whether there is a fair partition of the marbles.

    Input

    Each line in the input file describes one collection of marbles to be divided. The lines contain six non-negative integers n1 , . . . , n6 , where ni is the number of marbles of value i. So, the example from above would be described by the input-line "1 0 1 2 0 0". The maximum total number of marbles will be 20000.
    The last line of the input file will be "0 0 0 0 0 0"; do not process this line.

    Output

    For each collection, output "Collection #k:", where k is the number of the test case, and then either "Can be divided." or "Can't be divided.". 
    Output a blank line after each test case.

    Sample Input

    1 0 1 2 0 0 
    1 0 0 0 1 1 
    0 0 0 0 0 0 

    Sample Output

    Collection #1:
    Can't be divided.
    
    Collection #2:
    Can be divided.

    卡了我有这么久了,终于弄清楚了这道题。。同时也对多重背包有了自己的理解。
    多重背包就是为了解决0,1背包在面临大量数据时候的无力。
    简言之,多重背包题目是每种物品的数量不止一件,而且可能出奇的多。这时候又像是完全背包,又像是01背包,当然,你完全可以照着01背包的思路写,把大量的同种物品当成一件一件的,但是结果绝对是TLE。

    所以多重背包应运而生。
    多重背包是这样的:循环每种物品,如果当前物品量*价值 已经大于等于 背包量,那就进行一次完全背包,(因为在有限的背包量时,完全可以把物品量看成无限多)。。。而且完全背包相较而言更为省时。
    刚刚吴小珺同学还在纠结为什么这里能用完全背包,再解释一下,就是无论用完全背包还是01背包,目的都是在当前种物品里面,往背包里面塞尽可能多的量。。因此,如果此时物品量足够多,为什么不用完全背包来狠命的往包里塞东西?(怎么塞物品都还有多。。)。。。而且吴小珺同学,这个时候不要纠结能不能恰好放得下,完全背包恰好放不下,那01背包也放不下啊。。我只要求当前状态最优解即可。

    ***********************紧跟上面的来讲,如果物品量*价值<背包量,这个时候就要用01背包来做了,但是要用到一点状态压缩的思想来缩小时间占用。。。。即,用每次在小于总量的情况下,分别塞 1、2、4、8.。。2^k个物品,这样就能大限度的减小时间(关于为何能用这样表示而不丢失状态,专门的资料里有讲这种状态压缩方法)。

    好了,贴代码更加好讲
    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    int f[120005];
    int rec[6];
    int main()
    {
        int n;
        int i,j,k;
        int count=0;
        while (1)
        {
            int sum=0;
            for (i=0; i<6; i++)
            {
                scanf("%d",&rec[i]);
                sum+=rec[i]*(i+1);
            }
            if (!sum) break;  
            printf("Collection #%d:
    ",++count);
            if (sum%2)   //如果总量为奇数,根本就不要进行下去,不可能均分。
            {
                puts("Can't be divided.");
                putchar('
    ');
                continue;
            }
            for (i=0; i<=sum/2; i++)
                f[i]=0;
            for (i=0; i<6; i++)
            {
                if (!rec[i]) continue;
                if (rec[i]*(i+1)>=sum/2) //如果可以完全背包,则进行完全背包
                {
                    for (int v=i+1; v<=sum/2; v++)
                        if (f[v]<f[v-i-1]+i+1) f[v]=f[v-i-1]+i+1;
                }
                else
                {
                    int cur;
                    for (cur=1; cur<rec[i]; cur=cur*2) //进行01背包
                    {
                        for (k=sum/2; k>=cur*(i+1); k--)
                        {
                            if (f[k]<f[k-cur*(i+1)]+cur*(i+1))
                                f[k]=f[k-cur*(i+1)]+cur*(i+1);
                        }
                        rec[i]-=cur;
                    }
                    for (k=sum/2;k>=rec[i]*(i+1);k--) //因为模拟下就知道,按上面的01背包,肯定有物品漏掉,此时再补充好漏掉的状态
                    {
                        if (f[k]<f[k-rec[i]*(i+1)]+rec[i]*(i+1))
                                f[k]=f[k-rec[i]*(i+1)]+rec[i]*(i+1);
                    }
                }
            }
    
            if (f[sum/2]==sum/2) //如果能均分,则必定成真。
                puts("Can be divided.");
            else
                puts("Can't be divided.");
            putchar('
    ');
    
        }
        return 0;
    }
     
  • 相关阅读:
    UITableView 排序、删除
    iOS中arc的设置
    dynamics ax 2009 distinct实现及数组集合
    将关系数据库映射到业务实体
    常见负载均衡实现
    ibatis经验
    百度贴吧10亿量级LAMP架构分享
    dynamics ax 2009 字段类似的表绑定界面注意
    [转]大型动态应用系统框架
    .net 发展历程
  • 原文地址:https://www.cnblogs.com/kkrisen/p/3232937.html
Copyright © 2011-2022 走看看