Problem U

来源:互联网 发布:ios微信多开软件 编辑:程序博客网 时间:2024/05/22 16:55

简单题意

有分别价值为1,2,3,4,5,6的6种物品,每种价值物品有相对应的数量,问能否将物品分成两份,使得两份总价值相等。

解题思路形成过程

老师上课讲的例题,主要思想就是把一个多重背包问题,转化为01背包或完全背包来解决。用三个数组:c是费用,w是价值,m是数量,如果物品足够塞满背包转化为完全背包问题,否则转化为01背包问题。

感想

学会了一个套路,将多重背包问题,转换为01背包或完全背包的问题

AC代码

#include<iostream>
#include<stdio.h>
#include<fstream>
using namespace std;
const int INF=100000000;
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;  
    }
    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(){
    ifstream cin("in.txt");
    freopen("in.txt","r",stdin);
    int sum,c[7],w[7],m[7],cas=0;
    while(cin>>m[1]>>m[2]>>m[3]>>m[4]>>m[5]>>m[6]&&(m[1]||m[2]||m[3]||m[4]||m[5]||m[6])){    
        sum=0;
        for(int 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(int i=1;i<=sum;i++)
                f[i]=-INF;
                f[0]=0;
            for(int i=1;i<=6;i++)
                mutiple_pack(f,c[i],w[i],m[i]);//c是费用,w是价值,m是数量
            if(f[v]<0){
                puts("Can't be divided.\n");
            }else{
                puts("Can be divided.\n");
            }
        }
    }
    return 0;
}



0 0