Dividing

来源:互联网 发布:618也买酒淘宝店 编辑:程序博客网 时间:2024/06/06 05:03

T - Dividing

Time Limit:1000MS     MemoryLimit:10000KB     64bit IO Format:%I64d& %I64u

Submit Status

Description

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

Input

Each line in theinput file describes one collection of marbles to be divided. The lines containsix non-negative integers n1 , . . . , n6 , where ni is the number of marblesof 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 processthis line.

Output

For eachcollection, output "Collection #k:", where k is the number of thetest case, and then either "Can be divided." or "Can't bedivided.". 
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 bedivided.

 

Collection #2:

Can be divided.

 

 

 思路:

     就是多重背包转化为0-1和完全背包的问题。

如果直接按多重背包做会超时,所以要用二进制优化。


模型:

 

有N种物品和一个容量为V的背包。第i种物品最多有n[i]件可用,每件费用是c[i],价值是w[i]。求解将哪些物品装入背包可使这些物品的费用总和不跨越背包涵量,且价值总和最大。

 

办法:

 

根蒂根基算法

 

这题目和完全背包题目很类似。根蒂根基的方程只需将完全背包题目的方程略微一改即可,因为对于第i种物品有n[i]+1种策略:取0件,取1件……取n[i]件。令f[i][v]默示前i种物品恰放入一个容量为v的背包的最大权值,则有状况转移方程:

 

f[i][v]=max{f[i-1][v-k*c[i]]+k*w[i]|0<=k<=n[i]}

 

错杂度是O(V*Σn[i])。

 

转化为01背包题目

 

另一种好想好写的根蒂根基办法是转化为01背包求解:把第i种物品换成n[i]件01背包中的物品,则获得了物品数为Σn[i]的01背包题目,直接求解,错杂度仍然是O(V*Σn[i])。

 

然则我们期望将它转化为01背包题目之后可以或许像完全背包一样降落错杂度。仍然推敲二进制的思惟,我们推敲把第i种物品换成若干件物品,使得原题目中第i种物品可取的每种策略——取0..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,就将这种 物品分成系数分别为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])种物品,将原题目转化为了错杂度为<math>O(V*Σlogn[i])的01背包题目,是很大的改进。

 

以上内容来自背包九讲之多重背包题目


 

AC代码:


#include<iostream>#include<algorithm>#include<cstring>#include<cstdio>using namespace std;int dp[60060];const int T = 0x3f3f3f3f;void INIT(int k){for(int i=0;i<=k;++i){dp[i]= T;}dp[0]=0;}int main(){int a[10];int i,j,k,sum,cnt=1;while(cnt){sum=0;for(i=1;i<=6;++i){scanf("%d",&a[i]);sum+=a[i]*i;}if(sum==0)break;printf("Collection #%d:\n",cnt++);if(sum&1){printf("Can't be divided.\n\n");continue;}sum/=2;INIT(sum);for(i=1;i<=6;++i){if(sum<=a[i]*i)//完全背包{for(j=i;j<=sum;++j){dp[j]=min(dp[j],dp[j-i]+i);}}else//0-1背包{k=1;while(k<a[i]){for(j=sum;j>=i*k;--j){ dp[j]=min(dp[j],dp[j-i*k]+i*k);}a[i]-=k;k*=2;}if(a[i]){ for(j=sum;j>=i*a[i];--j) {dp[j]=min(dp[j],dp[j-i*a[i]]+i*a[i]);     }}}}if(dp[sum]==sum)printf("Can be divided.\n\n");elseprintf("Can't be divided.\n\n");}return 0;}


0 0
原创粉丝点击