[洛谷]P1021 邮票面值设计 (#搜索+dp)

探讨在有限邮票种类和数量下,如何设计邮票面值以覆盖最大连续邮资值的问题。采用深度优先搜索和动态规划算法,寻找最优面值组合。

题目描述

给定一个信封,最多只允许粘贴NN张邮票,计算在给定KK(N+K≤15N+K≤15)种邮票的情况下(假定所有的邮票数量都足够),如何设计邮票的面值,能得到最大值MAXMAX,使在11至MAXMAX之间的每一个邮资值都能得到。

例如,N=3N=3,K=2K=2,如果面值分别为11分、44分,则在11分~66分之间的每一个邮资值都能得到(当然还有88分、99分和1212分);如果面值分别为11分、33分,则在11分~77分之间的每一个邮资值都能得到。可以验证当N=3N=3,K=2K=2时,77分就是可以得到的连续的邮资最大值,所以MAX=7MAX=7,面值分别为11分、33分。

输入格式

22个整数,代表NN,KK。

输出格式

22行。第一行若干个数字,表示选择的面值,从小到大排序。

第二行,输出“MAX=SMAX=S”,SS表示最大的面值。

输入输出样例

输入 #1复制

3 2

输出 #1复制

1 3
MAX=7

思路

#include <stdio.h>
#include <iostream>
#include <memory.h>
#define inf 2e9+7
using namespace std;
int n,k,s,stamp[21],dp[21*21],maxn(-1),ans[21];
void dfs(int i)
{
	register int j;
	if(i>k)//如果最大面值超过k 
	{
		int maxx(0);//这个组合的最大面值 
		memset(dp,0,sizeof(dp));
		while(dp[maxx]<=n)//判断邮票值能否为maxx 
		{
			maxx++;
			dp[maxx]=inf;
			for(j=1;j<=k;j++)
			{
				if(maxx-stamp[j]<0) break;//如果一张邮票面值大于所求值的话(此时stamp一定单调递增) ,就结束循环 
				dp[maxx]=min(dp[maxx],dp[maxx-stamp[j]]+1);//dp数组存储达到一个面值所需要的最小的邮票数
			}
		}
		if(maxx-1>maxn)
		{
			for(j=1;j<=k;j++)
			{
				ans[j]=stamp[j];
			}
			maxn=maxx-1;
			return;
		}
	}
	else
	{
		for(j=stamp[i-1]+1;j<=stamp[i-1]*n+1;j++)//一张邮票可以贴m张,因此下一张邮票必须小于上一张*m+1 
		{
			stamp[i]=j;
			dfs(i+1);
		}
	}
}
signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	register int i;
	cin>>n>>k;
	stamp[1]=1;
	dfs(2);
	for(i=1;i<=k;i++)
	{
		cout<<ans[i]<<' ';
	}cout<<endl;
	cout<<"MAX="<<maxn<<endl;
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值