清橙OJ A1123. 邮票面值设计

题目来源:http://www.tsinsen.com/A1123

A1123. 邮票面值设计

时间限制:1.0s   内存限制:256.0MB  

试题来源

NOIP1999 提高组

问题描述

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

  例如,N=3K=2,如果面值分别为1分、4分,则在1分~6分之间的每一个邮资值都能得到(当然还有8分、9分和12分);如果面值分别为1分、3分,则在1分~7分之间的每一个邮资值都能得到。可以验证当N=3K=2时,7分就是可以得到的连续的邮资最大值,所以MAX=7,面值分别为1分、3分。

输入格式

  一行,两个数NK

输出格式

  两行,第一行升序输出设计的邮票面值,第二行输出“MAX=xx”(不含引号),其中xx为所求的能得到的连续邮资最大值。

样例输入

3 2

样例输出

1 3
MAX=7

-----------------------------------------------------

解题思路

总体的解题思路是深搜,即设计好了前ind个面值,对第(ind+1)个面值进行深搜。深搜的下界是当前最大面值+1,下界是当前可以达到的最大连续邮资+1,因为上界再大的话“最大连续邮资+1”这个值就取不到了,这样就不连续了。

      对于每一步的设计方案,要计算最大连续邮资。方法是暴力枚举+动态规划。枚举所有可能取到的邮资idp[i]表示在这种面值设计方案下,得到该邮资的最小邮票个数,如果dp[i]>n,那么最大连续邮资就是i-1.

-----------------------------------------------------

代码 

#include
#include
using namespace std;

const int NMAX = 15;
const int KMAX = 15;
const int INFI = 1000000;

int n,k;								// n: 邮票数; k: 邮资种数
int enu[KMAX] = {}, des[KMAX];			// enu: 此次迭代的各个邮资; des: 最优邮资
int ans = 0;							// 能得到的连续邮资最大值

int ComputeMax(int ind)					// 根据当前设计的方案计算最大连续邮资
{
	int i = 0, j = 0, possMax = n*enu[ind];			// 当前方案下可能达到的最大邮资
	int *dp = new int[possMax+1]();					// dp[i]:面值为i所需的邮票数
	memset(dp, INFI, (possMax+1)*sizeof(int));		// 设初值
	dp[0] = 0;										// 邮资0不需要邮票
	for (i=1; i<=possMax; i++)
	{
		for (j=ind; j>=0; j--)						// 使用面值为邮票enu[j]
		{
			if (enu[j]<=i)
			{
				dp[i] = dp[i]<=(dp[i-enu[j]]+1)? dp[i]:(dp[i-enu[j]]+1);
			}
		}
		if (dp[i]>n)								// 邮资为i时需要的邮票数已经超过n
		{
			break;									// 跳出循环
		}
	}
	delete[] dp;							// 释放内存
	return i-1;								// 最大连续邮资为i-1
}


void dfs(int ind, int val)				// ind:当前在设计第ind个面值, val: 当前设计的第ind面值是val
{
	enu[ind] = val;						// 第ind个面值是val
	int i = 0;
	int currentMax = ComputeMax(ind);	// 计算当前面值组合下的最大连续邮资
	if (ind==k-1)						// 如果已经用完了所有邮资总数
	{
		if (currentMax>ans)				// 维护最大值
		{
			ans = currentMax;
			for (i=0; i> n >> k;
	//enu[0] = 1;						// 第一个面值一定是1
	dfs(0,1);						
	for (int i=0; i

你可能感兴趣的:(清橙OJ)