算法提高(VIP)——邮票面值设计

题目描述
给定一个信封,最多只允许粘贴 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;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值