DP——一维数组求解背包问题

#背包问题是给定物体价值和重量,给定背包大小,求最优值的问题,大致分三种,01背包,完全背包和多重背包,其中01背包为基础,另外两种都可化为01背包。

#01背包是指所有的物品都只有一件,拥有独自的价值,完全背包是每件物品都有无数件,多重背包是物品有指定的有限数目件。对于完全背包和多重背包,将重复数目的物品拆分成01背包问题下相同价值的物品即可。

#具体动态规划的解法原理这里不再赘述,这篇文章将通过HDO1171的一道例题理一遍背包问题思路。

#问题

Big Event in HDU

Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 48724    Accepted Submission(s): 16680


Problem Description
Nowadays, we all know that Computer College is the biggest department in HDU. But, maybe you don't know that Computer College had ever been split into Computer College and Software College in 2002.
The splitting is absolutely a big event in HDU! At the same time, it is a trouble thing too. All facilities must go halves. First, all facilities are assessed, and two facilities are thought to be same if they have the same value. It is assumed that there is N (0<N<1000) kinds of facilities (different value, different kinds).
 

Input
Input contains multiple test cases. Each test case starts with a number N (0 < N <= 50 -- the total number of different facilities). The next N lines contain an integer V (0<V<=50 --value of facility) and an integer M (0<M<=100 --corresponding number of the facilities) each. You can assume that all V are different.
A test case starting with a negative integer terminates input and this test case is not to be processed.
 

Output
For each case, print one line containing two integers A and B which denote the value of Computer College and Software College will get respectively. A and B should be as equal as possible. At the same time, you should guarantee that A is not less than B.
 

Sample Input
 
 
2 10 1 20 1 3 10 1 20 2 30 1 -1
 

Sample Output
 
 
20 10 40 40

这是一道特殊的背包问题,我们要使A和B的和尽量靠近,也就是A和B都尽量靠近总价值的一半,且A大于B。物品是不占空间的,那么可以使总价值一半作为背包容量,这样就能求解出最接近于一半价值的并且小于一半价值的价值总和。

(........明白了使用二维数组并顺利解开这道题后)

画一张表手动画画就会发现,填表的时候每个格的值是通过其左上方的值确定的(背包容量在x方向,从1开始递增,物品序号在y方向的表格),如果我们从右方开始填表,那么第i行第j个格及以后的值都与此格右上方的值无关了,仅仅此格与其正上方的值有关,我们在确定此格值后便可直接用此值覆盖其上方值,故仅需一维数组即可。

使用右方开始填写的顺序还有一个好处,状态转移方程中有对于j(背包容量)的判断,如果是从左开始时在j小于物体重量时都是需要填0的,通常还要写个if-else,但从右往左只需写个for,终止于j<w[i](重量)就行了,代码省了几行,不过需要初始化数组为0,否则会有某些位置没能填上值的错误。

#AC码

#include<iostream>
#include <string.h>
#include <algorithm>
using namespace std;
int va[5555];
int dp[255555];
int main()
{
    int n;
    while(cin>>n,n>0)
    {
        memset(dp,0,sizeof(dp));
        int sum=0;
        int l=1;
        int t,a,mid;
        for(int i=0;i<n;i++)
        {
            cin>>a>>t;
            sum+=a*t;
            while(t--)
                va[l++]=a;
        }
        mid=sum/2;
        for(int i=1;i<l;i++)
        for(int j=mid;j>=va[i];j--)
            dp[j]=max(dp[j],dp[j-va[i]]+va[i]);
        cout<<sum-dp[mid]<<" "<<dp[mid]<<endl;
    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值