多重背包问题

来源:互联网 发布:seo关键字是什么 编辑:程序博客网 时间:2024/05/17 18:18

多重背包模板:
#include <iostream>#include <stdio.h>#include <string.h>#define N 1000         //物品个数 #define M 100000000    //所有物品可能的最大价值 using namespace std;int m[N],c[N],w[N],f[M];int V;int max(int a,int b){return a>b?a:b;}void ZeroOnePack(int cost,int weight){    int v;    for(v=V;v>=cost;v--) f[v]=max(f[v],f[v-cost]+weight);}void CompletePack(int cost,int weight){    int v;    for(v=cost;v<=V;v++)        f[v]=max(f[v],f[v-cost]+weight);}void MultiplePack(int cost,int weight,int amount){    int k;    if(cost*amount>=V)    {        CompletePack(cost,weight);        return;    }/* 二进制优化    k=1;    while(k<amount)    {        ZeroOnePack(k*cost,k*weight);        amount=amount-k;        k=k*2;    }    ZeroOnePack(amount*cost,amount*weight);*/}int main(){    int n,i;    scanf("%d %d",&n,&V);                                                   // 两种不同的初始化方式,根据情况自行选择     //memset(f,0,sizeof(f[0])*(V+1));              // 只希望价格尽量大     //memset(f,-M,sizeof(f[0])*(V+1));f[0]=0;      // 要求恰好装满背包     for(i=0;i<n;i++) scanf("%d %d %d",m+i,c+i,w+i);    for(i=0;i<n;i++) MultiplePack(c[i],w[i],m[i]);    printf("%d\n",f[V]);    return 0;}

比直接拆成一件一件物品的01背包省时间,因为多了一步二进制优化拆解 (例子节选自网络)

 假如给了我们 价值为 2,但是数量却是10 的物品,我们应该把10给拆开,要知道二进制可是能够表示任何数的,所以10 就是可以有1,2, 4,8之内的数把它组成,一开始我们选上 1了,然后让10-1=9,再选上2,9-2=7,在选上 4,7-4=3,而这时的3<8了,所以我们就是可以得出 10由 1,2,4,3,来组成,就是这个数量为1,2,3,4的物品了,那么他们的价值是什么呢,是2,4,6,8,也就说给我们的价值为2,数量是10的这批货物,已经转化成了价值分别是2,4,6,8元的货物了,每种仅有一件。这就是二进制优化的思想。 
 那为什么会有完全背包和01 背包的不同使用加判断呢?
①当数据很大,大于背包的容纳量时,我们就在这个物品中取几件,取得量未知,就理解为无限
②小于容纳量的就转化为01背包来处理,省时间。(用二进制优化,不要拆分一件一件一般都会超时)


例题:POJ1014 
Dividing
Time Limit: 1000MS Memory Limit: 10000KTotal Submissions: 71475 Accepted: 18637

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.
#include <iostream>#include <stdio.h>#include <string.h>using namespace std;const int AX = 500000+666;int dp[AX];int a[1000];int main(){int kk = 0;int x;int sum;while(1){sum = 0;int ans = 0;for(int i=1;i<=6;i++){scanf("%d",&x);sum += x*i;  int k = 1;           //二进制优化while(k<=x){ a[++ans] = k*i;x -= k;k*=2;}if(x) a[++ans] = x*i;}if(sum == 0){break;}printf("Collection #%d:\n",++kk);if(sum%2 == 1){printf("Can't be divided.\n\n");continue;}memset(dp,0,sizeof(dp));dp[0] = 1;                       //本题0的方案一定存在for(int i=1;i<=ans;i++){for(int j=sum;j>=a[i];j--){if(dp[j-a[i]]){dp[j] = 1;}}}if(dp[sum/2]){printf("Can be divided.\n\n");}else{printf("Can't be divided.\n\n");}}return 0;}


原创粉丝点击