您的位置:首页 > 其它

Problem U

2016-05-29 22:43 267 查看
简单题意

有分别价值为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;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  dp 多重背包