Dividing【暑期集训B题】【多重背包】【二进制优化】

        这道题就得要讲到二进制优化算法了,对于1,2,4,8,......,2^n,......2的每一阶的数都能由它其中的某几阶数的和来表示——前文

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. 
InputEach line in the input describes one collection of marbles to be divided. The lines consist of six non-negative integers n1, n2, ..., 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. 
OutputFor each colletcion, 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.

        对于题目给的例子,永远是偏小的,他们可以用各种超时的方式写出来,当然AC永远是不会让你AC的。

        思路:题目告诉了我们价值分别为1~6的石头一个他们的数量,我们要做的就是判断它们能否被等额平分。我们来思考这样一个问题,假如有22块价值为1的石头,我们将它们分成2的阶的和,会留下些什么?22=2+4+16,不会留下东西。那么再换个例子(这可不是我没有深思熟虑的结果,只是在举例子而已)32怎么说?32=1+2+4+8+16+1!它多出了1。那么如果用的是“<=”岂不是可以避免这类情况?但是那就会出现一种多拿的情况,那不就很尴尬了吗?

        所以,我们对1~6每个石头,我们可以将它们的数量用二的阶乘的和来表示,这就是二进制优化的由来了。

        但是上述的想法和接下来的代码都仅是使用于这道题的,二进制优化的实例为,对于10,可以有1,2,4,8组成,10=2+8,但是这样是不行的,这会让我们多拿些东西,譬如当上述成员存在时,我们有可能背包里放的是1+2+8的东西,这么就很尴尬了。所以我们要记录已经放了的东西,让K*2小于等于数量才是正解,对于多处的数我们用一个a[i]-x存储下来就行了,例如10可以有1,2,4和3存储一样。

二进制优化代码:

        int cnt=0;

        for(int i=1; i<=6; i++)

        {

            int k=1;

            int x=0;

            while(k<a[i])

            {

                b[cnt++]=k*i;

                x+=k;

                k*=2;

            }

            if(a[i]>x)

            {

                b[cnt++]=(a[i]-x)*i;

            }

        }


完整代码:

#include 
#include 
#include 
using namespace std;
int a[7];
int b[50000];
int dp[500000];
int main()
{
    int Case=0;
    while(scanf("%d %d %d %d %d %d",&a[1],&a[2],&a[3],&a[4],&a[5],&a[6])!=EOF)
    {
        Case++;
        if(Case>1)cout<x)
            {
                b[cnt++]=(a[i]-x)*i;
            }
        }
        dp[0]=1;
        for(int i=0; i=b[i]; j--)
            {
                if(dp[j-b[i]]) dp[j]=1;
            }
        }
        if(dp[mid]) printf("Can be divided.\n");
        else printf("Can't be divided.\n");
    }
    return 0;
}

你可能感兴趣的:(背包)