书山有径勤为路>>>>>>>>

<<<<<<<<学海无涯苦作舟!

DP(五)——简单的多重背包

POJ 1014    http://poj.org/problem?id=1014

题意是这样的:有分别价值为1,2,3,4,5,6的6种物品,输入6个数字,

表示相应价值的物品的数量,问一下能不能将物品分成两份,

是两份的总价值相等,其中一个物品不能切开,只能分给其中的某一方,

当输入六个0是(即没有物品了),这程序结束,总物品的总个数不超过20000

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.
下面一个是个高效的算法,但是不是最高的。
复制代码
View Code
#include<iostream>
using namespace std;
#define size 70010
int f[2*size];
int a[10];
int MultP(int n, int v){
    int i, j, k, amount;
    memset(f, 0, sizeof(f));
    for(i=1; i<=n; i++){ //枚举物品的总数量,(这里数量=价值)
        if(a[i]*i>=v){ //完全背包,(a[i]表示第i件物品的数量) 
            for(j=i; j<=v; j++)
                f[j] = max(f[j], f[j-i]+i);     
        }
        else{ //01背包
            k=1;
            amount = a[i];
            while(k<amount){
                for(j=v; j>=k*i; j--)
                    f[j] = max(f[j], f[j-k*i]+k*i);
                amount -= k;
                k = k*2;
            }
            for(j=v; j>=amount*i; j--)
                f[j] = max(f[j], f[j-amount*i]+amount*i);
        }
    }
    return f[v];
}
int main()
{
    int Case=0, flag, i, sum;
    while(1)
    {
        Case++;
        sum = 0;
        for(i=1; i<=6; i++)
        {
            cin>>a[i];
            sum+=a[i]*i;
        }
        flag = 0;
        for(i=1; i<7; i++)
        {
            if(a[i]!=0)
            {
                flag = 1;
                break;
            }
        }
        if(flag == 0) break;
        if(sum%2==1)
        {
            cout<<"Collection #"<<Case<<":"<<endl<<"Can't be divided."<<endl<<endl;
            continue;
        }
        i = MultP(6, sum/2);
        if(i==(sum/2)) cout<<"Collection #"<<Case<<":"<<endl<<"Can be divided."<<endl<<endl;
        else cout<<"Collection #"<<Case<<":"<<endl<<"Can't be divided."<<endl<<endl;
    }
}
复制代码

 

下面给出一个不是很高效的算法,在POJ上是超时的。

复制代码
View Code
#include<iostream>
using namespace std;
#define size 20005
int num[7];
bool f[size];
int main()
{
int ex = 0, sum, i, j, k, Max, t, flag;
while(cin>>num[0]>>num[1]>>num[2]>>num[3]>>num[4]>>num[5])
{
ex++;
sum=0, flag=0;
for(i=0; i<6; i++) sum+=num[i]*(i+1);
if(sum==0) break;
if(sum%2==1)
{
cout<<"Collection #"<<ex<<":"<<endl<<"Can't be divided."<<endl<<endl;
continue;
}
//接下来多重背包
Max = 0;
f[0] = true; //这个是初始化问题
for(i=0; i<6; i++) //枚举每件物品
{
for(k=Max; k>=0; k--) //01背包的做法
{
if(f[k]==true) //判断此时f[k]是否已经存在,只有存在了,才可以继续DP
{
for(j=1; j<=num[i]; j++) //件数,从1开始
{
t = k+j*(i+1); //此时的价值
f[t] = true;
if(t>Max) Max = t;
if(Max==(sum/2))
{
flag = 1;
break;
}
}
}
if(flag) break;
}
if(flag) break;
}
if(flag) cout<<"Collection #"<<ex<<":"<<endl<<"Can be divided."<<endl<<endl;
else cout<<"Collection #"<<ex<<":"<<endl<<"Can't be divided."<<endl<<endl;
}
}
复制代码


 

posted on   More study needed.  阅读(265)  评论(0编辑  收藏  举报

编辑推荐:
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
阅读排行:
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架
< 2011年11月 >
30 31 1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 1 2 3
4 5 6 7 8 9 10

导航

统计

书山有径勤为路>>>>>>>>

<<<<<<<<学海无涯苦作舟!

点击右上角即可分享
微信分享提示