题目链接: 点击打开链接
题目大意: 分弹珠
思路: 动态规划,多重背包
分析:
多重背包问题,第一次没优化超时了,根据背包问题九讲上的叙述稍微优化了一下,过了。先把每种物品分成若干个物品,每个物品有一个系数,1,2,4... . ,每个物品的重量和价值是原本的值乘上这个系数,这样就转化成一个01背包问题,接着就好办了。
代码:
#include <cstdio>
#include <memory.h>
#include <algorithm>
using namespace std;
const int maxv = 60000 + 100;
const int maxn = 1000 + 100;
int number[7], values[maxn], n, dp[maxv], value;
void change2zeroone()
{
n = 0;
for (int i = 1; i <= 6; ++i)
for (int coe = 1; coe <= number[i]; coe <<= 1)
{
int temp_coe = coe << 1, temp = number[i] - temp_coe + 1;
if (temp < 0)
coe = number[i] - coe + 1;
values[n++] = coe * i;
if (temp < 0) break;
}
}
void solve()
{
change2zeroone();
memset(dp, 0, sizeof(dp));
for (int i = 0; i < n; ++i)
for (int j = value; j >= values[i]; --j)
dp[j] = max(dp[j], dp[j - values[i]] + values[i]);
}
void output(int kase)
{
printf("Collection #%d:\n", kase);
if (dp[value] == value)
printf("Can be divided.\n\n");
else
printf("Can't be divided.\n\n");
}
int main()
{
int kase = 0;
while (1)
{
bool exit = true;
value = 0;
for (int i = 1; i <= 6; ++i) {
scanf("%d", &number[i]);
value += i * number[i];
if (number[i] != 0) exit = false;
}
if (exit) break;
if (value % 2 != 0) {
printf("Collection #%d:\n", ++kase);
printf("Can't be divided.\n\n");
continue;
}
value /= 2;
solve();
output(++kase);
}
return 0;
}
还有一段根据背包问题九讲伪代码改的:
#include <cstdio>
#include <memory.h>
#include <algorithm>
using namespace std;
const int maxv = 60000 + 100;
int amount[7], dp[maxv], V;
void ZeroOnePack(int cost, int value)
{
for (int i = V; i >= cost; --i)
dp[i] = max(dp[i], dp[i - cost] + value);
}
void ComPack(int cost, int value)
{
for (int i = cost; i <= V; ++i)
dp[i] = max(dp[i], dp[i - cost] + value);
}
void MulPack(int cost, int value, int amount)
{
if (cost * amount > V) {
ComPack(cost, value);
return;
}
for (int i = 1; i <= amount; i <<= 1) {
ZeroOnePack(cost * i, value * i);
amount -= i;
}
ZeroOnePack(cost * amount, value * amount);
}
void solve()
{
memset(dp, 0, sizeof(dp));
for (int i = 1; i <= 6; ++i)
MulPack(i, i, amount[i]);
}
void output(int kase)
{
printf("Collection #%d:\n", kase);
if (dp[V] == V)
printf("Can be divided.\n\n");
else
printf("Can't be divided.\n\n");
}
int main()
{
int kase = 0;
while (1)
{
bool exit = true;
V = 0;
for (int i = 1; i <= 6; ++i) {
scanf("%d", &amount[i]);
V += i * amount[i];
if (amount[i] != 0) exit = false;
}
if (exit) break;
if (V % 2 != 0) {
printf("Collection #%d:\n", ++kase);
printf("Can't be divided.\n\n");
continue;
}
V /= 2;
solve();
output(++kase);
}
return 0;
}