POJ1014-Dividing-多重背包

本代码中的几个函数可以作为“0-1背包”、“完全背包” 和“多重背包”的模板:

 

#include <iostream> 
#define INF 100000000  
using namespace std;
  
int f[240005];  //f[j]相当于f[i][j]: 考虑1...i个物品,恰好放到容量为j,所能达到的最大价值 
int v; //背包容量 

//处理一个完全背包 (该种物品不限量)
void complete_pack(int *a, int c, int w)  
{  
    for(int i = c; i <= v; i++)  
        a[i] = max(a[i], a[i - c] + w);  
}  

//处理一个 01背包 (该种物品只有一个) 
void zeroone_pack(int *a, int c, int w)  
{  
    for(int i = v; i >= c; i--)  
        a[i] = max(a[i], a[i - c] + w);  
}  

//处理一个多重背包 (该种物品指定上限) 
void mutiple_pack(int *a, int c, int w, int m)  
{  
    //该种物品足以塞满背包-->转化为完全背包 
    if(c * m >= v){  
        complete_pack(a, c, w);  
        return;  
    }
    
    /*二进制思想拆分:多重背包中的一个物品--变成-->0-1背包中的多个物品
      容量:2^0    2^1    2^2    2^k    m-∑前面             ***保证k达到最大值                                                 
      价值:2^0*c  2^1*c  2^2*c  2^k*c  (m-∑前面 )*c
    */
    int k = 1;  
    while(k < m)  
    {  
        zeroone_pack(a, k * c, k * w);  
        m = m - k;  
        k = 2 * k;  
    }  
    zeroone_pack(a, c * m, w * m);  
}  

int main()  
{  
    //freopen("d:/data.in","r",stdin);  
    //freopen("d:/data.out","w",stdout);  
    int sum, i, c[7], w[7], m[7],cas = 0;  
    while(scanf("%d%d%d%d%d%d", &m[1], &m[2], &m[3], &m[4], &m[5], &m[6])){  
        if(m[1] == 0 && m[2] == 0 && m[3] == 0 && m[4] == 0 && m[5] == 0 && m[6] == 0)  
        break;  
        sum = 0;  
        for(i = 1; i <= 6; i++){  
            c[i] = w[i] = i;  
            sum += c[i] * m[i];  
        }  
        printf("Collection #%d:\n", ++cas);  
        if(sum & 1){  
            puts("Can't be divided.\n");  
        }else{  
            sum /= 2;  
            v = sum;
            
            for(i = 1; i <= sum; i++)  
                  f[i] = -INF;  
            f[0] = 0;  
              
            for(i = 1; i <= 6; i++)  
                  mutiple_pack(f, c[i], w[i], m[i]);  
            if(f[v] < 0){  
                puts("Can't be divided.\n");  
            }else{  
                puts("Can be divided.\n");  
            }  
        }  
    }  
    
    system("pause");
    return 0;  
} 
 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值