、# XDOJ 174题分配宝藏(动态规划01背包拓展)
本文章仅解释本题思路,(本文假设读者已经了解01背包)。关于动态规划详细解答请参考博客XDOJ(智慧平台)–分配宝藏(用动态规划dp算法解决)(C语言)。关于01背包还有这个比较详细的b站视频动态规划dp01背包
题目描述
标题
分配宝藏
类别
综合
时间限制
2S
内存限制
256Kb
问题描述
两个寻宝者找到一个宝藏,里面包含n件物品,每件物品的价值分别是W[0],W[1],…W[n-1]。
SumA代表寻宝者A所获物品价值总和,SumB代表寻宝者B所获物品价值总和,请问怎么分配才能使得两人所获物品价值总和差距最小,即两人所获物品价值总和之差的绝对值|SumA - SumB|最小。输入说明
输入数据由两行构成:
第一行为一个正整数n,表示物品个数,其中0<n<=200。
第二行有n个正整数,分别代表每件物品的价值W[i],其中0<W[i]<=200。输出说明
对于每组数据,输出一个整数|SumA-SumB|,表示两人所获物品价值总和之差的最小值。
输入样例
1 2 3 4
输出样例
0
思路
1.从分配和价值总和可以看出这题是个01背包问题。
2.背包是什么呢?物品是什么呢?价值、重量分别对应什么呢?
3.题目中说两人价值总和之差最小,不妨设价值之差最小时A的价值为sum[a],B的价值为sum[b],(且sum[a] < sum[b]),价值总和为SUM。
4.由数学知识可以知道,sum[a] - sum[b]的绝对值要最小,就要使SUM - sum[a]的值最小。
5.这步是关键点。由上面题意可以知道,要使得SUM - sum[a]的值最小,换句话说就是在 ⌊ S U M 2 ⌋ \lfloor \frac{SUM}{2} \rfloor ⌊2SUM⌋(向下取整)范围内,sum[a]能分配到的最大价值。那么就找到背包和价值了:
a的价值就是背包, ⌊ S U M 2 ⌋ \lfloor \frac{SUM}{2} \rfloor ⌊2SUM⌋就是背包容量,宝藏的价值既是物品的价值,也是物品的重量
那么就可以给出代码
#include <iostream>
#include <algorithm>
using namespace std;
int main(){
int n, sum=0;
int w[201], dp[20001] = {0};// w[]:宝藏价值。dp[]:A分到的宝藏价值
cin >> n;
// 读取数据
for (int i = 0; i < n; i++) {
cin >> w[i];
sum += w[i];
}
// 处理数据
/*状态转移公式为:dp[j] = max(dp[j], dp[j-w[i]] + w[i])
这里w[i]既是重量,也是价值*/
int target = sum/2; // target 是目标的背包容量
for (int i = 0; i < n; i++)
for (int j = target; j >= w[i]; j--)
if (w[i] <= j)
dp[j] = max(dp[j], dp[j-w[i]]+w[i]);
// 输出数据
cout << sum-dp[target]-dp[target];
//sum-dp[target]就是目标状态下B分到的价值,
//dp[target]就是目标状态下A分到的价值。
return 0;
}