题意:
有 6 种硬币,每一种价格使用最优的策略使所需硬币数最少。问价格 1-100 所需要的平均硬币数以及最大需要的硬币数。
思路:
1. 完全背包的变型,因为涉及到找零,所以有状态转移 : dp[v] = min(dp[v - w[i]] + 1, dp[v + w[i]] + 1)
2. 我们可以采取两步走的方法避免深度搜索,首先利用完全背包求的不找零的情况下,容量 v 的最优策略:dp[v] = min(dp[v], dp[v - w[i]] + 1)
3. 然后在上面的结果下再利用一次完全背包:dp[v] = min(dp[v], dp[v + w[i]] + 1)
4. 数组要记得开大,比如下面的case: 1 95 96 97 98 99 结果应该是:12.29 25,可以想象:dp[48] = 12 * 2,即 (99 - 95) * 12. 上届很大了 : 99 * 12
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 1500;
const int infs = 0x3ffffff;
int dp[maxn + 1];
int main()
{
int cases;
scanf("%d", &cases);
while (cases--)
{
int w[10];
for (int i = 0; i < 6; ++i)
scanf("%d", &w[i]);
dp[0] = 0;
for (int v = 1; v < maxn; ++v)
dp[v] = infs;
for (int i = 0; i < 6; ++i)
for (int v = w[i]; v < maxn; ++v)
if (dp[v - w[i]] != infs)
dp[v] = min(dp[v], dp[v - w[i]] + 1);
for (int i = 0; i < 6; ++i)
for (int v = maxn - w[i] - 1; v >= 0; --v)
if (dp[v + w[i]] != infs)
dp[v] = min(dp[v], dp[v + w[i]] + 1);
int ave = 0, maxret = 0;
for (int v = 1; v <= 100; ++v)
{
ave += dp[v];
maxret = max(maxret, dp[v]);
}
double ans = ave;
ans /= 100;
printf("%.2lf %d\n", ans, maxret);
}
return 0;
}