题目描述
给定一个信封,最多只允许粘贴 N 张邮票,计算在给定 K 种邮票的情况下(假定所有的邮票数量都足够)。
如何设计邮票的面值,能得到最大值 MAX,使在 1~MAX 之间的每一个邮资值都能得到。
例如:N = 3,K = 2,如果面值分别为 1 分、4 分,则在 1 分~ 6 分之间的每一个邮资值都能得到。
如果面值分别为 1 分、 3 分,则在 1 分~7 分之间的每一个邮资值都能得到。
可以验证当 N = 3,K = 2 时,7 分就是可以得到的连续的邮资最大值,所以 MAX = 7,面值分别为 1 分、 3 分。
输入格式
一行,两个数 N、K
输出格式
第一行升序输出设计的邮票面值。
第二行输出 “MAX=xx”(不含引号),其中 xx 为所求的能得到的连续邮资最大值。
样例输入
3 2
样例输出
1 3
MAX=7
数据范围
N + K ≤ 13
题解
DFS & 动态规划:
f[i]
:凑出 i
至少需要几张邮票。
枚举邮票面值
:假设当前的邮票是第 n 张
起点
:第 n - 1 张邮票面值 + 1终点
:前 n - 1 张邮票能凑出来的连续最大值 + 1
#include <iostream>
using namespace std;
int n, k, MAX;
int f[10010], a[20], s[20];
int dp(int u) // 计算前 u 张邮票能凑出来的连续最大值
{
for (int i = 1; i <= a[u] * n; i ++) f[i] = 0x3f3f3f3f;
for (int i = 1; i <= u; i ++)
for (int j = a[i]; j <= a[u] * n; j ++)
f[j] = min(f[j], f[j - a[i]] + 1);
for (int i = 1; i <= a[u] * n; i ++)
if(f[i] > n) return i - 1;
}
void dfs(int u, int num)
{
if(u == k + 1)
{
if(num > MAX)
{
MAX = num;
for (int i = 1; i < u; i ++) s[i] = a[i];
}
return;
}
for (int i = a[u - 1] + 1; i <= num + 1; i ++)
{
a[u] = i;
dfs(u + 1, dp(u));
}
}
int main()
{
cin >> n >> k;
dfs(1, 0);
for (int i = 1; i <= k; i ++) cout << s[i] << " ";
cout << endl;
cout << "MAX=" << MAX << endl;
return 0;
}