poj1014完全背包 hdu2191多重背包 经典二进制优化

多重背包或者完全背包转换成 01 背包问题就是多了个二进制优化
把它的件数C 用分解成若干个件数的集合
这里面数字可以组合成任意小于等于C 的件数,而且不会重复
之所以叫二进制分解,是因为这样分解可以用数字的二进制形式来解释

比如:7的二进制 7 = 111 它可以分解成 001 010 100 这三个数可以组合成任意小于等于7 的数
而且每种组合都会得到不同的数
15 = 1111 可分解成 0001  0010  0100  1000 四个数字

如果13 = 1101 则分解为 0001 0010 0100 0110 前三个数字可以组合成 7以内任意一个数
加上 0110 = 6 可以组合成任意一个大于6 小于13的数,虽然有重复但总是能把13以内所有的数都考虑到了

分解为了1,2,4,8.....2*(k-1),和总的物品数目减去 2*(k-1)
 一共分成了k+1份

基于这种思想去把多件物品转换为,多种一件物品,就可用01 背包求解了



Dividing
Time Limit: 1000MS Memory Limit: 10000K
Total Submissions: 67052 Accepted: 17422

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.



题意:

          价值为1  2  3  4  5  6  的物品,他们的数目就是题目中的input

          求:把这些物品分成两半,这两堆中价值相等,但是每一件物品是不能分割的

完全背包或者DFS都可以做出来的



#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;

int a[10],sum;
int str[1000],pos;
int dp[61000];

int main()
{
    int coun=1;
    while(scanf("%d%d%d%d%d%d",&a[1],&a[2],&a[3],&a[4],&a[5],&a[6])!=EOF)
    {
        if(a[1]+a[2]+a[3]+a[4]+a[5]+a[6]==0)
            break;
        sum=(a[1]*1+a[2]*2+a[3]*3+a[4]*4+a[5]*5+a[6]*6);
        printf("Collection #%d:\n",coun++);
        if(sum%2==1){
            puts("Can't be divided.\n");
            continue;
        }
        sum/=2;

//-------------------------二进制优化------------------------------------------//
        pos=0;
        for(int i=1;i<=6;i++){
            for(int j=1;j<=a[i];j<<=1){
                str[pos++]=j*i;
                a[i]-=j;
            }

            if(a[i]>0)
                str[pos++]=a[i]*i;
        }
//---------------------------0 1背包-------------------------------------------//
        memset(dp,0,sizeof(dp));
        for(int i=0;i<pos;i++)
            for(int j=sum;j>=str[i];j--)
                dp[j]=max(dp[j],dp[j-str[i]]+str[i]);


        if(dp[sum]!=sum)
            puts("Can't be divided.\n");
        else
            puts("Can be divided.\n");
    }
    return 0;
}




悼念512汶川大地震遇难同胞——珍惜现在,感恩生活

Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 23210    Accepted Submission(s): 9803


Problem Description
急!灾区的食物依然短缺!
为了挽救灾区同胞的生命,心系灾区同胞的你准备自己采购一些粮食支援灾区,现在假设你一共有资金n元,而市场有m种大米,每种大米都是袋装产品,其价格不等,并且只能整袋购买。
请问:你用有限的资金最多能采购多少公斤粮食呢?

后记:
人生是一个充满了变数的生命过程,天灾、人祸、病痛是我们生命历程中不可预知的威胁。
月有阴晴圆缺,人有旦夕祸福,未来对于我们而言是一个未知数。那么,我们要做的就应该是珍惜现在,感恩生活——
感谢父母,他们给予我们生命,抚养我们成人;
感谢老师,他们授给我们知识,教我们做人
感谢朋友,他们让我们感受到世界的温暖;
感谢对手,他们令我们不断进取、努力。 
同样,我们也要感谢痛苦与艰辛带给我们的财富~


 

Input
输入数据首先包含一个正整数C,表示有C组测试用例,每组测试用例的第一行是两个整数n和m(1<=n<=100, 1<=m<=100),分别表示经费的金额和大米的种类,然后是m行数据,每行包含3个数p,h和c(1<=p<=20,1<=h<=200,1<=c<=20),分别表示每袋的价格、每袋的重量以及对应种类大米的袋数。
 

Output
对于每组测试数据,请输出能够购买大米的最多重量,你可以假设经费买不光所有的大米,并且经费你可以不用完。每个实例的输出占一行。
 

Sample Input
  
  
1 8 2 2 100 4 4 100 2
 

Sample Output
  
  
400
 


多重背包问题


#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;

//-------------------下面是需要输入的三个值----------------------------//
struct EEE
{
    int value;
    int weight;
    int num;
}a[105];
//-----------------------下面总金额和n种大米---------------------------//
int cash,n;

//---------------下面是二进制分解后得到的每一份重量和大小----------------//
int coun,weigh[1010],size[1010];
//---------------------------------------------------------------------//
int dp[110];

int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        coun=0;
        scanf("%d%d",&cash,&n);
        for(int i=0;i<n;i++){
            scanf("%d%d%d",&a[i].value,&a[i].weight,&a[i].num);
//---------------------下面在输入后进行分解------------------------------//
            for(int j=1;j<=a[i].num;j<<=1){
                //左移一位等价于乘以  2
                weigh[coun]=j*a[i].weight;
                size[coun++]=j*a[i].value;
                a[i].num-=j;
            }
//-----------------------处理剩余的部分----------------------------------//
            if(a[i].num>0){
                weigh[coun]=a[i].num*a[i].weight;
                size[coun++]=a[i].num*a[i].value;
            }
        }

//--------------------0  1  背包问题求解--------------------------------//
        memset(dp,0,sizeof(dp));
        for(int i=0;i<coun;i++)
            for(int j=cash;j>=size[i];j--)
                dp[j]=max(dp[j],dp[j-size[i]]+weigh[i]);

//------------------------------------------------------------------------//
        printf("%d\n",dp[cash]);
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值