题目:
问题描述
给定一个信封,最多只允许粘贴N张邮票,计算在给定K(N+K≤13)种邮票的情况下(假定所有的邮票数量都足够),如何设计邮票的面值,能得到最大值MAX,使在1~MAX之间的每一个邮资值都能得到。
例如,N=3,K=2,如果面值分别为1分、4分,则在1分~6分之间的每一个邮资值都能得到(当然还有8分、9分和12分);如果面值分别为1分、3分,则在1分~7分之间的每一个邮资值都能得到。可以验证当N=3,K=2时,7分就是可以得到的连续的邮资最大值,所以MAX=7,面值分别为1分、3分。
输入格式
一行,两个数N、K
输出格式
两行,第一行升序输出设计的邮票面值,第二行输出“MAX=xx”(不含引号),其中xx为所求的能得到的连续邮资最大值。
样例输入
3 2
样例输出
1 3
MAX=7
思路:
1.用dfs搜邮票面值的组合
子树的方向:
dfs(第i个邮票,第i个邮票的面值){
dfs(第i+1个邮票,第i+1个邮票的面值)
}
边界:
for (int j = (i_value+1); j <= (now_value + 1); ++j){
//1.下一张邮票面值一定比这张大
//2.前i张邮票能凑成的连续最大邮资为now_value
//则第i+1张邮票价值不超过now_value+1
//否则now_value+1这个面值就凑不了了
dfs(i + 1, j);
}
2.用dp确定每种邮票组合的连续最大邮资
//递推:其中1<=j<=k
f[i] = min(f[i], f[i - val[j]] + 1)
完整代码:
#include<bits/stdc++.h>
using namespace std;
int n, k, ans = 0;
int val[15];//面值表,长度k,from 1
int result[15];//最大面值的表
int dp(int len) {
//由当前面值表得到连续最大面值
//表长自定
int f[200] = {0};//f[面值]=最少张数
f[0] = 0;
f[1] = 1;
int this_max = 1;
for (int i = 2; i <= (val[len] * n); ++i) {
//面值最大值为
++this_max;
f[i] = 100000;
for (int j = 1; j <= len; ++j) {
if ((i - val[j]) < 0) {
break;
}
f[i] = min(f[i], f[i - val[j]] + 1);
}
if (f[i] > n) {
--this_max;
break;
}
}
return this_max;
}
void dfs(int i, int i_value) {
//第i个,面值i_value
if (i > k) {
return;
}
//更新
val[i] = i_value;
int now_value = dp(i);
if (now_value > ans) {
for (int j = 1; j <= k; ++j) {
result[j] = val[j];
}
ans = now_value;
}
//子树
for (int j = (i_value + 1); j <= (now_value + 1); ++j) {
dfs(i + 1, j);
}
}
int main() {
cin >> n >> k;
dfs(1, 1);
for (int i = 1; i <= k; ++i) {
cout << result[i] << ' ';
}
cout << endl << "MAX=" << ans;
return 0;
}