多重背包之 HDU -1171Big Event in HDU &HDU -2191悼念512汶川大地震遇难同胞——珍惜现在,感恩生活

时间:2023-12-21 16:41:56

这两道题都是多重背包的基础题,前面的安格题意是:给出每个物体的价值和物体的数量,如何分使得A,B所得价值最接近并且A的价值不能小于B,就类似于NYOJ上的那个邮票分你一半那个意思,只不过这里不是一个而是多个,所以多重背包

前一个题是将总和的一半当作背包的容量来求,代码如下

 #include <iostream>
#include <cstdio>
#include <cstring> using namespace std; int dp[];
int cnt[];
int value[];
int main()
{
int n;
while (~scanf("%d", &n) && n > )
{
memset(dp, , sizeof(dp));
int sum = ;
for (int i = ; i < n; i++)
{
scanf("%d %d", &value[i], &cnt[i]);
sum += value[i] * cnt[i];
}
int v = sum / ;
for (int i = ; i < n; i++)
{
for (int j = v; j >= value[i]; j--)//01背包
{
for (int k = ; k <= cnt[i] && k * value[i] <= j; k++)//遍历每一种
dp[j] = max(dp[j], dp[j - k * value[i]] + k * value[i]);
}
}
printf("%d %d\n", sum - dp[v], dp[v]);
}
return ;
}

第二个题一样的,也是多重背包

代码如下

 #include <iostream>
#include <cstdio>
#include <cstring> using namespace std;
const int N = ;
int weight[N];
int value[N];
int cnt[N];
int dp[N];
int main()
{
int T;
int n, money;
scanf("%d", &T);
while (T--)
{
scanf("%d %d", &money, &n);
for (int i = ; i < n; i++)
scanf("%d %d %d", &weight[i], &value[i], &cnt[i]);
memset(dp, , sizeof(dp));
for (int i = ; i < n; i++)
{
for (int j = money; j >= weight[i]; j--)//01背包
{
for (int k = ; k <= cnt[i] && k * weight[i] <= money; k++)//遍历每一种情况,所以上面是01背包,如果上面用完全背包,就相当于取重了
if (j >= k * weight[i])
dp[j] = max(dp[j], dp[j - k * weight[i]] + k * value[i]);
}
}
printf("%d\n", dp[money]);
}
return ;
}