原题链接: http://acm.hdu.edu.cn/showproblem.php?pid=1171
大意是: 给定n个物品的价值,还有对应的数量。然后将这些物品分成A, B两部分,使每部分的总价值尽可能的相等,且A的价值不小于B。
开始我想的将它转成0-1背包问题。求B的最大价值,它的背包容量为总价值/2。
递推式是
下面是用动态规划做的,样例都已通过,可是超时超空间:再下面是重新写的代码。
这个代码错误的原因是:数组范围开辟有问题,最大的价值,即背包容量应该是50*50*100,所以只能用一维数组来解决0-1背包,代码在后面。
递推式是
#include
#include
using namespace std;
int value[5005] = { 0 };
int d[5005][2505] = { 0 };
int main()
{
int n;
while (true){
int flag = 0;
int sum = 0;
int num = 0;
cin >> n;
if (n < 0) break;
int v, m;
for (int i = 0; i < n; i++){
cin >> v >> m;
for (int j = 0; j < m; j++){
value[flag++] = v;
}
sum += v*m;//sum是背包容积,即总价值
num += m;//num是物品的个数
}
for (int i = 0; i <= sum / 2; i++){
if (value[0] <= i)
d[0][i] = value[0];
}
for (int i = 1; i < num; i++){
for (int j = 1; j <= sum / 2; j++){
if (j - value[i] >= 0)
d[i][j] = max(d[i - 1][j], d[i - 1][j - value[i]] + value[i]);
else
d[i][j] = d[i - 1][j];
}
}
cout << sum-d[num-1][sum/2] << " " << d[num-1][sum/2] << endl;
}
return 0;
}
下面是更新代码,用一维数组解决0-1背包,已AC:
//#include "stdafx.h"
#include //memset的头文件,之前竟然没用过
#include
#include
using namespace std;
int value[5005] = { 0 };
int d[250005] = { 0 };
int main()
{
int n;
while (true) {
int flag = 0;
int sum = 0;
int num = 0;
cin >> n;
if (n < 0) break;
int v, m;
for (int i = 0; i < n; i++) {
cin >> v >> m;
for (int j = 0; j < m; j++) {
value[flag++] = v;
}
sum += v*m;//sum是背包容积,即总价值
num += m;//num是物品的个数
}
memset(d, 0, sizeof(d));
for (int i = 0; i <= sum/2; i++) {
for (int j = 0; j < num; j++) {
if(i-value[j]>=0)
d[i] = max(d[i], d[i - value[j]] + value[j]);
}
}
cout << sum - d[sum/2] << " " << d[sum / 2] << endl;
}
return 0;
}
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=1176
大意是:有0-10这11个点,馅饼在不同的时间落在这些点上。但是有个人初始位置在5,每秒只能移动一个单位, 求它最多能拿到多少馅饼。
这题是和数字三角形差不多的题,就是要从最后开始记录,每次记录都是和下一次的时间点的位置有关。
设a[i][j]表示第j秒有馅饼落在i位置
d[i][j]表示第i个位置时,第j秒取得的最大馅饼数量。
d[i][j] = max( d[i - 1][j + 1], d[i][j + 1] , d[i+1][j+1] )+ a[i][j] ;
递推式为上式,注意处理边界条件即可。代码如下:
#include
#include
#include
#include
#include "stdio.h"
using namespace std;
int a[11][100005] = { 0 };//a[i][j]表示第j秒有一个馅饼落在第i个地方
int d[11][100005]; //其实如果空间不足,用一个数组也行
int main()
{
int n;
while (true){
memset(a, 0, sizeof(a));
scanf("%d", &n);
if (n == 0) break;
int x, t, maxt = 0;
for (int i = 0; i < n; i++){
scanf("%d%d", &x, &t);
a[x][t]++;
maxt = max(maxt, t);//找出最大的t来,便于遍历数组
}
for (int i = 0; i<11; i++)
d[i][maxt] = a[i][maxt];
for (int j = maxt - 1; j >= 0; j--){
d[10][j] = max(d[9][j + 1], d[10][j + 1]) + a[10][j];
d[0][j] = max(d[1][j + 1], d[0][j + 1]) + a[0][j];
for (int i = 1; i < 10; i++){
d[i][j] = max(d[i - 1][j + 1], d[i][j + 1]);
d[i][j] = max(d[i][j],d[i+1][j+1]) + a[i][j];
}
}
printf("%d\n", d[5][0]);
}
return 0;
}