hdu - 2602 - Bone Collector

题意:N块石头,每块石头有各自的价值与体积,将石头放入体积为V的背包中,能获得的最大价值是多少。

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2602

——>>0-1背包问题,设d[i][j]为将 前i块石头 放入 容量为j的背包 中的 最大价值,那么第i块石头,要么放,要么不放,放的话,d[i][j] = d[i-1][j-vol[i]],不放的话,d[i][j] = d[i-1][j],取两者中的最大者。

#include <iostream>
#include <algorithm>

using namespace std;

const int maxn = 1000 + 10;     //N <= 1000 , V <= 1000
int d[maxn][maxn];      //d[i][j]表示将 前i块石头 放入 容量为j的背包 中的 最大价值

int main()
{
    int T, N, V, i, j, val[maxn], vol[maxn];
    cin>>T;
    while(T--)
    {
        cin>>N>>V;
        for(i = 1; i <= N; i++)     //输入价值
            cin>>val[i];
        for(i = 1; i <= N; i++)     //输入体积
            cin>>vol[i];
        for(i = 0; i <= V; i++) d[0][V] = 0;        //任何一个背包,不入石头,则得到的价值为0
        for(i = 1; i <= N; i++)     //共N块石头
            for(j = 0; j <= V; j++)     //容量从0到V,因为是整数,恰好可作数组下标
            {
                if(j >= vol[i])     //如果背包放得下这块石头
                    d[i][j] = max(d[i-1][j], d[i-1][j-vol[i]]+val[i]);      //取放与不放这块石头较大者
                else d[i][j] = d[i-1][j];       //肯定取不了这块石头
            }
        cout<<d[N][V]<<endl;        //将前N块石头放在容量为N的背包
    }
    return 0;
}


今天学了个滚动数组,再做一次,换了种方法:

——>>滚动数组感悟:

例:0-1背包问题:

n件物品:

物品体积(V):1   2   3

物品重量(W):3   2   1

背包容量(Q):4

记f[i][j]表示在前i件物品中选择物品放到容量(体积)不超过j的背包中的最大重量。

则状态转移方程为:f[i][j] = max(f[i-1][j], f[i-1][j-V] +W);

看这个样子

int d[n+10];全部初始为0!!!

for(i = 1; i <= n; i++)

for(j = Q; j >= 0; j--)

d[j] = max(d[j], d[j-V] + W);

请观:

处理第1个物品时:

d[4] = max(d[4], d[4-1] + 3] = max(d[4], d[3] + 3) = max(0, 0 + 3) = 3;

d[3] = max(d[3], d[3-1] + 3] = max(d[3], d[2] + 3) = max(0, 0 + 3) = 3;

d[2] = max(d[2], d[2-1] + 3] = max(d[2], d[1] + 3) = max(0, 0 + 3) = 3;

d[1] = max(d[1], d[1-1] + 3] = max(d[1], d[0] + 3) = max(0, 0 + 3) = 3;

d[0] = 0;

---------------------------------------------------------------------------------------------

处理第2个物品时:

d[4] = max(d[4]d[4-2] + 2] = max(d[4], d[2] + 2) = max(3, 3 + 2) = 5;   //d[4]记算前,实际上是f[i-1][4],d[4-2]+2是f[i-1][4-2],都是上一层的结果;

d[3] = max(d[3]d[3-2] + 2] = max(d[3], d[1] + 2) = max(3, 3 + 2) = 5;   //d[3]记算前,实际上是f[i-1][3],d[3-2]+2是f[i-1][3-2],都是上一层的结果;

d[2] = max(d[2]d[2-2] + 2] = max(d[2], d[0] + 2) = max(3, 0 + 2) = 3;   //d[2]记算前,实际上是f[i-1][2],d[2-2]+2是f[i-1][2-2],都是上一层的结果;

d[1] = 3;   //d[1]记算前,实际上是f[i-1][1],都是上一层的结果;

d[0] = 0;   //d[0]记算前,实际上是f[i-1][0],都是上一层的结果;

---------------------------------------------------------------------------------------------

处理第3个物品时:

d[4] = max(d[4], d[4-3] + 1] = max(d[4], d[1] + 1) = max(5, 3 + 1) = 5;   //同上

d[3] = max(d[3], d[3-3] + 1] = max(d[3], d[0] + 1) = max(5, 0 + 1) = 5;  //同上

d[2] = 3;   //同上

d[1] = 3;   //同上

d[0] = 0;   //同上

可以看出,这样做用新的d[j]利用上一层d[j]的值经处理覆盖了原来的值,不再将上一层的值保存在一个数组中,达到了同样的效果,

开始我在疑惑,为什么要for(j = Q;, j >=0; j--),为什么不从小到大,写下,通也!

若是从小到大:

d[0] = 0;

d[1] = max(d[1], d[1-1] + 3] = max(d[1], d[0] + 3) = max(0, 0 + 3) = 3;

d[2] = max(d[2], d[2-1] + 3] = max(d[2], d[1] + 3) = max(0, 3 + 3) = 6;

......可以看到,这样做d[i]更新时,利用的不是上一层的结果,而是现在这一层的结果,当然错误啦……

#include <cstdio>
#include <algorithm>
#include <cstring>

using namespace std;

const int maxn = 1000 + 10;

int main()
{
    int T, N, V, val[maxn], vol[maxn], d[maxn], i, j;
    scanf("%d", &T);
    while(T--)
    {
        scanf("%d%d", &N, &V);
        for(i = 1; i <= N; i++) scanf("%d", &val[i]);
        for(i = 1; i <= N; i++) scanf("%d", &vol[i]);
        memset(d, 0, sizeof(d));
        for(i = 1; i <= N; i++)
            for(j = V; j >= 0; j--)
                if(j - vol[i] >= 0) d[j] = max(d[j], d[j-vol[i]] + val[i]);
        printf("%d\n", d[V]);
    }
    return 0;
}

小心初始化d数组和判断条件!!!

一时兴起,再来个Java的,只是在初始化d 的时候,WA了两次,第一次,没从0开始,第二次,终点设V成了N……

import java.util.Scanner;
public class Main {
	static final int maxn = 1000 + 10;
	public static void main(String[] args) {
		int T, N, V, val[] = new int[maxn], vol[] = new int[maxn], d[] = new int[maxn];
		Scanner cin = new Scanner(System.in);
		T = cin.nextInt();
		while(T-->0){
			N = cin.nextInt();
			V = cin.nextInt();
			for(int i = 1; i <= N; i++) val[i] = cin.nextInt();
			for(int i = 1; i <= N; i++) vol[i] = cin.nextInt();
			for(int i = 0; i <= V; i++) d[i] = 0;
			for(int i = 1; i <= N; i++)
				for(int j = V; j >= 0; j--)
					if(j - vol[i] >= 0) d[j] = d[j] < d[j-vol[i]]+val[i] ? d[j-vol[i]]+val[i] : d[j];
			System.out.println(d[V]);
		}
		cin.close();
	}
}


你可能感兴趣的:(hdu - 2602 - Bone Collector)