动态规划+深搜 解邮票面值设计问题

动态规划+深搜 解邮票面值设计问题

题目描述

给定一个信封,最多只允许粘贴N张邮票,计算在给定K(N+K≤15)种邮票的情况下(假定所有的邮票数量都足够),如何设计邮票的面值,能得到最大值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分。

输入格式

2个整数,代表N,K。

输出格式

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

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

输入输出样例

输入 #1

3 2

输出 #1

1 3
MAX=7

解题思路

用f[i]表示凑出i元需要的最少邮票数,状态转移方程f[j]=min(f[j],f[j-stm[i]]+1)

再结合DFS,详见代码注释

完整代码

#include <iostream>
#include <string.h>
using namespace std;
int n,k,stm[15],res[15],maxx=0,f[5000];
//stm[i]暂存邮票面值,res[i]和 max表示输出的结果,f[i]表示凑出 i元需要的最少邮票数 

//动归
int dp(int num) 
  {
  	memset(f,1,sizeof(f));//赋一个大值,注意这里 memset函数所赋的值并不是简单的 1 
  	f[0]=0;//边界,拼 0元需要 0张邮票 
  	for(int i=1;i<=num;i++) //从第一张到第num张枚举 
  	   {
  	   	for(int j=stm[i];j<=stm[num]*n;j++) //从stm[i]开始凑,到全部取最大面值的邮票,最多可以凑到stm[num]*n 
  	   	   {
  	   	   	 if(f[j-stm[i]]<n)
  	   	   	    f[j]=min(f[j],f[j-stm[i]]+1);//取小的 
		   }
	   }
	for(int i=1;i<=stm[num]*n;i++)
      if(f[i]>n)//如果所需最小的个数大于 n就意味着这种情况不符合,但 f[i-1]是符合的
        return i-1;  
  	return stm[num]*n; //如果从 1到 stm[num]*n都满足,则它就是要找的最大连续数  
  } 

//深搜
void dfs(int num) 
  {
  	if(num==k+1)//如果所有的都已找完,则和 maxx比较保留大的 
  	  {
  	  	int tmp=dp(num-1);
  	  	if(tmp>maxx)
  	  	  {
  	  	  	maxx=tmp;
  	  	  	memcpy(res,stm,sizeof(res));//保存需要的邮票面值,即需要输出的结果 
		  }
	  }
	else //否则继续找 
	  {
	  	int end=dp(num-1);
	  	for(int i=stm[num-1]+1;i<=end+1;i++)
	  	  {
	  	  	stm[num]=i;
	  	  	dfs(num+1);
	  	  	stm[num]=0;
		  }
	  }
  }
  
int main()
  {
  	cin>>n>>k;
  	dfs(1);//从第一张开始找 
  	for(int i=1;i<=k;i++)
  	  cout<<res[i]<<" ";
  	cout<<endl;
  	cout<<"MAX="<<maxx;
  	return 0;
  }
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
DESCRIPTION: 1.Analyze Problem A : sorted stamps array A={ai} ai: one stamp element in array n: array size, that is number of elements in array r: desired value of stamps F(n,r):expected result, minimum number of stamps for a given value r from n size array. S: selected stamps array S={si} 2.Choose Algorithm a.Greedy algorithm seems to be a good choice, try to solve it in O(n), i try divide array into subarry B={bi}, r should larger than every elemnt in B that is r>bi and suppose bk is the smallest element in B, so that r= bk%r, f(i,r)=(bk/r), F(n,r)=∑f(i,r). The main idea is to choose the last element who larger than desired value each time. However,it can not give us optimal solution in some condition, like A={8,5,4,1}, if r=10, this algoritm will give a solution F(n,r)=3, S={8,1,1},but the optimal solution should be F(n,r)=2, S={5,5}. b.Full search so the straight forwards algorithm is to search for every solution in A for desired value directly.However, it will always take O(n!) to go through every combination. c.Dynamic programming, at last, I decide to choose dynamic programming. analyze optimal structure, suppose in A={ai}, for a specific stamp ak,there will be two cases it is choosen so that f(i,r)=1+f(i,r-ak) , 1<=i<=k, r>=ak it is not valid so that f(i,r)=f(i-1,r) 3.Design Dynamic programming optimal structure: Compute-opt(r)= 1 + Compute-opt(r-ai) value: Compute-opt(r) = ∞ (r < 0) Compute-opt(r) = 0 (r = 0) Compute-opt(r) = 1+{Compute-opt(r-ai)} ( 1=<i<=n, r>ai>0 ) Complexity :O(nr) Memory cost:O(n+r) Compute in a bottom-up style to recursive every desired value and array. store value of Compute-opt in memory for future use, so that we can easily get value from those memory in future recursive call, and avoid compute again, that is if the array is not change, you can easily fetch result any desired value j (j < r, r is the value using for compute ). 2.For User totally, I design a small command line for this machine list below 1.Manual Operation 2.Self Auto Testing 3.Check Results q.Quit Manual Operation: when select this machine will turn to be manual mode, ask person to input stamps and desired value; Self Auto Testing:when select this machine will turn to be auto mode, show the test case already design in code after that machine will quit automatically. Check Results: only be visiable in Manual Operation, people can check desired value for the array input before, the desired value should be no more than first time input. Quit, clean all the memory and quit system.

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值