NYOJ 860 又见01背包
2014-12-12 15:10
281 查看
这道题其实和一般的01背包没有什么区别,只是这道题目按照正常的思维去做不行了,因为容量太大,开个10^9的数组开不了,所以这时候就需要换种思维,这个题刚开始没理解,后来在网上在题解,发现都说是互换重量和价值,但是一直没理解什么意思,后来,仔细想了想那个最最基础的01背包是怎么推出来的才想通了, 也不能说是互换价值和重量,那样其实并不能加深理解,做完这个题之后,发现又对背包理解深了一点,写个博客,留下纪念
这道题很容易发现其实重量很大,达到10^9,但是价值很小啊,现在就来推一下这个所谓的“互换”是怎么来的 (其实我觉得还不如从最原始的来,不叫做“互换”好理解点), 最原始的那个式子
dp[i][j]表示当取 i 个, 重量为 j 的时候背包的最大价值,状态转移方程就是 dp[i][j] = max(dp[i - 1][j], dp[i-1][j - weight[i]] + value[i]), 这个式子的意思想必大家都明白吧,前面的那个意思是不取当前这个,后面的这个是取上当前这个物品, 后来再经空间优化之后变成了dp[j] = max(dp[j], dp[j - weight[i]] + value[i]), 仔细观察会发现二维数组时,那两种状态都是i - 1,所以就可以去掉,但是得注意,循环遍历的时候要逆序,正序的话就成完全背包了, 忘了说这个dp[j]表示什么了, dp[j]就是 当取到重量为j 的时候的最大价值。弄明白了这些。这时候就可以来看这个题了, 题目要求和普通的01背包一样,求能装的最大价值,普通方法就是直接找最大价值,现在要换种思维,找最小的重量, 因为同样价值,重量越小,那么最后能装的价值就可能越大,所以这个dp[i][j]就表示 当 取 i 个, 价值为j 的时候的最小重量,状态转移方程为 dp[i][j] = min(dp[i - 1][j], dp[i - 1][j - value[i]] + weight[i]), 和那个最初推的一样,不再罗嗦,空间优化之后状态转移方程为dp[j] = min(dp[j], dp[j - value[i]] + weight[i]), 同样的意思,dp[j]表示 价值为j 的时候的最小重量,到最后只要从最大价值往下遍历这个dp数组,只要找到dp[j] <= 背包重量的时候就直接输出 j , 这时候j就是最大的。
代码如下:
这道题很容易发现其实重量很大,达到10^9,但是价值很小啊,现在就来推一下这个所谓的“互换”是怎么来的 (其实我觉得还不如从最原始的来,不叫做“互换”好理解点), 最原始的那个式子
dp[i][j]表示当取 i 个, 重量为 j 的时候背包的最大价值,状态转移方程就是 dp[i][j] = max(dp[i - 1][j], dp[i-1][j - weight[i]] + value[i]), 这个式子的意思想必大家都明白吧,前面的那个意思是不取当前这个,后面的这个是取上当前这个物品, 后来再经空间优化之后变成了dp[j] = max(dp[j], dp[j - weight[i]] + value[i]), 仔细观察会发现二维数组时,那两种状态都是i - 1,所以就可以去掉,但是得注意,循环遍历的时候要逆序,正序的话就成完全背包了, 忘了说这个dp[j]表示什么了, dp[j]就是 当取到重量为j 的时候的最大价值。弄明白了这些。这时候就可以来看这个题了, 题目要求和普通的01背包一样,求能装的最大价值,普通方法就是直接找最大价值,现在要换种思维,找最小的重量, 因为同样价值,重量越小,那么最后能装的价值就可能越大,所以这个dp[i][j]就表示 当 取 i 个, 价值为j 的时候的最小重量,状态转移方程为 dp[i][j] = min(dp[i - 1][j], dp[i - 1][j - value[i]] + weight[i]), 和那个最初推的一样,不再罗嗦,空间优化之后状态转移方程为dp[j] = min(dp[j], dp[j - value[i]] + weight[i]), 同样的意思,dp[j]表示 价值为j 的时候的最小重量,到最后只要从最大价值往下遍历这个dp数组,只要找到dp[j] <= 背包重量的时候就直接输出 j , 这时候j就是最大的。
代码如下:
#include <stdio.h> #include <stdlib.h> #include <string.h> #define Min(a,b) a<b?a:b const int N = 10003; int dp ; int weight[102]; int value[102]; int main() { int n, w; while (scanf("%d %d", &n, &w) == 2) { int sum = 0; for (int i = 0; i < n; i++) { scanf("%d %d", &weight[i], &value[i]); sum += value[i];//sum保存所有的价值之和 } memset(dp, 0x3f, sizeof(dp));//初始化数组要为无穷大,因为是要找最小值,所以默认无穷大 dp[0] = 0; for (int i = 0; i < n; i++) { for (int j = sum; j >= value[i]; j--) dp[j] = Min(dp[j], dp[j - value[i]] + weight[i]); } for (int i = sum; i >=0; i--) if (dp[i] <= w) { printf("%d\n", i); break; } } return 0; }
相关文章推荐
- nyoj 860又见01背包(01背包)
- nyoj860 01背包变形-好题
- NYOJ 题目860 又见01背包
- 【志银】NYOJ《题目860》又见01背包
- NYOJ 题目860 又见01背包(01背包变形)
- NYOJ 题目860 又见01背包 (特别版01背包)
- nyoj860--又见01背包(01背包的另一种形态)
- nyoj--860--又见01背包--01背包的变形
- NYOJ 860 又见01背包
- nyoj 860又见01背包
- nyoj860又见01背包
- NYOJ 860 又见01背包
- NYOJ 860 又见01背包(01背包转移方程巧用)
- NYOJ 860 又见01背包
- NYOJ 860 又见01背包【01】
- NYOJ 860 又见01背包
- nyoj 860 (01背包 变形)
- NYOJ 860 又见01背包
- NYOJ 860 又见01背包
- NYOJ 860 特殊01背包