算法提高(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 
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;
}

你可能感兴趣的:(蓝桥杯练习系统,ADV-6,DFS,+,动态规划)