/*
连续邮资问题
算法设计:
该问题是设计最佳的邮票面值,用来表示最大的区间
对于连续邮姿问题,用n元组x[1:n]表示n种不同的邮票面值并约定它们从小到大排列。
整数r表示当前使用不超过m张邮票能贴出的最大连续邮资区间。
x[1] = 1是唯一的选择。此时最大连续邮资区间是[1:m]
接下来x[2]的可能取值范围是[2:m+1],这个取值范围就决定了x[2]应该怎么选,
只所以确定这样的范围是因为,至少要保证增加一个面值后,可以将区间增
大1一般情况下,已选定x[1:i-1],此时最大连续邮资区间是[1:r],则接下来
x[i]的可取值范围是[x[i-1]+1:r+1]。由此可以看出,在用回溯法时,可以用一棵树表示其
解空间。该解空间树中各结点的度随x的不同取值而变化。  设x[1~n]是从小到大排列的n种邮票面值。
首先x[1]=1 是毫无疑问的,否则最小邮资 1 无法支付。
面值为1的邮票构成的最大连续区间只能是[1,m] (只贴1张就是1……m张邮票全贴满是m)。
如果这时候再给我们第二种面额的邮票。因为它需要比x[1]大,所以最少只能是2;
又因为单纯由x[1]支付的邮资区间最大只到m,再往上就出现了断档,所以x[2]最大也只能取m+1
(如果再大的话,m+1这个值就无法正常表示)
同样的道理,假设前面k种邮票面值都已经有了,并且能构成[1, r]的连续邮资区间,
那么第k+1种邮票的面值必须满足:
x[k]+1 <= x[k+1] <= r+1
算法就是要找到这么多种可能情况下的最优方案  对于连续邮资问题,用n元组x[1:n]表示n种不同的邮票面值,并约定它们从小到大排列。
x[1] = 1是惟一的选择。在未确定剩余其它n-1种邮票面值的情况下,只用x[1]一种邮票面值,
所能得到的最大连续邮资区间是[1:m]。接下来,确定x[2]的取值范围,很明显,
x[2]的值最小可以取到2,因为x[1] 这时已经为1了。那么最大可以取的值呢?应当是m+1,
为什么?因为如果x[2]取m+2,则在这个方案中,邮资m+1不可能取得,
(这个时候,x[2:n]的任何一个面值是不能取的,因为就算只取一张,总和也会至少为m+2,
超过m+1了,反过来,如果只取x[1]面值,则就算把m张全取了,也只能凑到m)。所以,
在搜索第2张邮票的时候,搜索范围是2 ~ m+2(m+2不剪取)。在一般的情况下,已选定x[1:i-1],
最大连续邮资区间是[1:r]时,接下来x[i]的可取值范围是[x[i-1]+1 :r+1]。由此可以看出,
[x[i-1]+1 :r+1](为限界函数)在用回溯法解连续邮资问题时,可用树表示其解空间,
该解空间树中各结点的度随x的不同取值而变化。  现在可以大致画出该解空间树的结构。
现在的关键问题是,如何确定x3的取值范围?转换一下就是如何求得在x[1],x[2]面值确定的情况下,
用不超过m张邮票,所得到的最大连续邮资区间是多少?如果每一个这样的问题能够确定,
则解空间树已经构造好了(每一个的儿子结点为r-x[i-1]),我们就可以通过深度优先遍历的方式得到最佳面值设计
(每到达叶结点见比较更新)。  现在来看在x[1],x[2]面值确定的情况下,用不超过m张邮票,所得到的最大连续邮资区间是多少?
最大连续邮资区间总是以1作为起点的,所以我们用max来表示这个最大值,显然,max至少可以取到m,
因为即使不用x[2]面值,只用x[1]面值的情况下,所能得到的最大值就已经是m了。现在来看在x[1],
x[2]面值确定的情况下,用不超过m张邮票,max+1能不能取到?
假设在拼凑的过程中,x[2]面值的邮票取t张,则t>=0,t<=(max+1) /x[2] && t<=m
现在x[2]面值的邮票张数已经确定,原问题转化为另一个子问题,即,在x[1]面值确定的情况下,
用不超过m-t张邮票,max+1 - t*x[2] 能不能取到? 。。。。。。
到这一步就很容易理解了,因为x[1] 面值为1,所以如果要拼凑的值max+1- t*x[2] <= m-t的话,
则只用取max+1- t*x[2]张就可以拉。相反,如果max+1- t*x[2] > m-t的话,则是不可以满足的。  在下面的回溯法描述中,递归函数Backtrack实现对整个解空间的回溯搜索。
maxvalue记录当前已经找到的最大连续邮资区间,bestx是相应的当前最优解。
数组y用来记录当前已经选定的邮票面值x[1:i]能贴出各种邮资所需的最少邮票数。  也就是说,y[k]是用不超过m张面值为x[1:i]的邮票,贴出邮资k所需的最少邮票张数。
在函数Backtrack中,
当i>n时,表示算法已经搜索到一个叶结点,得到一个新的邮票面值设计方案x[1:n]。如果该方案能贴出的
最大连续邮资区间大于当前已经找到的最大连续邮资区间maxvalue,则更新当前最优值maxvalue和相应的最优解。
当i <= n时,当前扩展结点z是解空间中的一个内部结点,在该结点处x[1:i-1]
能贴出的最大最大邮资区间为r-1.因此在结点z处x[i]的可取范围是x[i-1]+1:r,
从而,结点z有r-x[i-1]个儿子结点。算法对当前扩展结点z的每一个儿子结点,
以深度优先的方式递归地对相应子树进行搜索  解空间是多叉树,孩子接点个数是每层都在变化的
*/
#include<iostream>
#include<Windows.h>
using namespace std;class Stamp
{
friend int MaxStamp(int  ,int  ,int []);private:// int Bound(int i);void Backtrack(int i,int r);int n;//邮票面值数int m;//每张信封最多允许贴的邮票数int maxvalue;//当前最优值int maxint;//大整数int maxl;//邮资上界int *x;//当前解int *y;//贴出各种邮资所需最少邮票数int *bestx;//当前最优解};void Stamp::Backtrack(int i,int r)
{/*计算X[1:i]的最大连续邮资区间,考虑到直接递归的求解复杂度太高,我们不妨尝试计算用不超过m张面值为x[1:i]的邮票贴出邮资k所需的最少邮票数y[k]。通过y[k]可以很快推出r的值。事实上,y[k]可以通过递推在O(n)时间内解决*/for(int j=0;j<=x[i-2]*(m-1);j++) //x[i-2]*(m-1)是第i-2层循环的一个上限,目的是找到r-1的值 if(y[j]<m){for(int k=1;k<=m-y[j];k++) //k是对表示j剩余的票数进行检查   {if(y[j]+k<y[j+x[i-1]*k])//x[i-1]*k是k张邮票能表示的最大邮资   //+j表示增加了i邮资后能   //判断新增加的能表示的邮资需要多少 {y[j+x[i-1]*k]=y[j]+k;//对第i-2层扩展一个x[i-1]后的邮资分布}}}//查看邮资范围扩大多少,然后查询y数组从而找到r while(y[r]<maxint) //计算X[1:i]的最大连续邮资区间{r++;}//搜索求出r-1的值,对应x[1:i-1]的在m张限制内的最大区间 if(i>n) // 如果到达发行邮票的张数,则更新最终结果值,并返回结果{if(r-1>maxvalue)  // 用r计算可贴出的连续邮资最大值,而maxStamp存放最终结果{maxvalue=r-1;for(int j=1;j<=n;j++)bestx[j]=x[j];  // 用x[i]表示当前以确定的第i+1张邮票的面值,bestx保存最终结果}return;}int *z=new int[maxl+1];for(int k=1;k<=maxl;k++)z[k]=y[k];//保留数据副本,以便返回上层时候能够恢复数据   //以上都是处理第i-1层及其之上的问题   for(int j=x[i-1]+1;j<=r;j++) //在第i层有这么多的孩子结点供选择   {x[i]=j;Backtrack(i+1,r);//返回上层恢复信息for(int k=1;k<=maxl;k++)y[k]=z[k];}delete[] z;
}int MaxStamp(int n,int m,int bestx[]){Stamp X;int maxint=32767;int maxl=1500;X.n=n;X.m=m;X.maxvalue=0;X.maxint=maxint;X.maxl=maxl;X.bestx=bestx;X.x=new int [n+1];X.y=new int [maxl+1];for(int i=0;i<=n;i++)X.x[i]=0;for(int i=1;i<=maxl;i++)X.y[i]=maxint;X.x[1]=1;X.y[0]=0;X.Backtrack(2,1);cout<<"当前最优解:";for(int i=1;i<=n;i++)cout<<bestx[i]<<"  ";cout<<endl;delete[] X.x;delete [] X.y;return X.maxvalue;
}void main(){int *bestx;int n;int m;cout<<"请输入邮票面值数:";cin>>n;cout<<"请输入每张信封最多允许贴的邮票数:";cin>>m;bestx=new int[n+1];for(int i=1;i<=n;i++)bestx[i]=0;cout<<"最大邮资:"<<MaxStamp(n,m,bestx)<<endl;Sleep(5000);}

连续邮资问题的回溯法解决办法相关推荐

  1. 回溯算法背包问题迭代c语言,回溯法解决0_1背包问题(迭代和递归)

    问题:0/1背包问题 例子:weight数组代表物品重量,value数组代表物品价值,M代表背包容量.背包是按单位价值递减的顺序排列的,即value[i]/weight[i]>value[i-1 ...

  2. 利用回溯法解决1-9之间添加+或-或使得运算结果为100的问题

    问题描述 编写一个在1,2,-,9(顺序不能变)数字之间插入+或-或什么都不插入,使得计算结果总是100的程序,并输出所有的可能性.例如:1 + 2 + 34 – 5 + 67 – 8 + 9 = 1 ...

  3. 回溯法解决0-1背包问题

    回溯法解决0-1背包问题 参考文章: (1)回溯法解决0-1背包问题 (2)https://www.cnblogs.com/womendouyiyang/p/10957527.html (3)http ...

  4. 编程解决素数环问题Java_回溯法解决素数环问题java实现

    素数环问题: 输入正整数n,把整数1,2,3--,n组成一个环,使得相邻两个整数之和均为素数,输出所有方案,注意同一个环应恰好输出一次.n<==16 样例输入: 6 样例输出: 1 4 3 2  ...

  5. 回溯法解决部落冲突问题

    回溯法解决部落冲突问题 实验内容 问题描述 思路分析 方法步骤 实验代码 实验内容 原始部落byteland中的居民为了争抢有限的资源,经常发生冲突.几乎每个居民都有它的仇敌.部落酋长为了组织一支保卫 ...

  6. 回溯法解决n皇后问题

    回溯法解决n皇后问题 题目要求: 在n×n格的棋盘上放置彼此不受攻击的n个皇后.按照国际象棋的规则,皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子.n后问题等价于在n×n格的棋盘上放置n个皇后, ...

  7. 回溯法解决力扣79题单词搜索

    回溯法解决力扣79题单词搜索 给定一个 m x n 二维字符网格 board 和一个字符串单词 word .如果 word 存在于网格中,返回 true :否则,返回 false . 单词必须按照字母 ...

  8. 回溯法解决工作分配问题

    回溯法解决工作分配问题 问题描述: 设有n件工作分配给n个人.为第i个人分配工作j所需的费用为c[i][j] .试设计一个算法,计算最佳工作分配方案,为每一个人都分配1 件不同的工作,并使总费用达到最 ...

  9. c语言 用回溯算法解决01背包问题,回溯法解决01背包问题

    <回溯法解决01背包问题>由会员分享,可在线阅读,更多相关<回溯法解决01背包问题(21页珍藏版)>请在人人文库网上搜索. 1.回溯法解决01背包问题,回溯法解决01背包问题, ...

最新文章

  1. 修改mysql的用户名和密码
  2. 【JavaSE02】Java基本语法-注意点
  3. thinkphp-条件判断-范围判断-NOTBETWEEN
  4. 一个c语言程序什么时候结束,新人求救,写了一个C语言程序,输入完数据后就结束了!!!...
  5. Java领域的对象如何传输-如何解决报错的问题呢?
  6. 通过带数据盘的自定义镜像来创建使用应用程序网关的虚拟机规模集
  7. jetpack的camerax_Android开发-Jetpack组件CameraX
  8. Jersey 异常处理
  9. Bootstrap Paginator 分页插件参数介绍及使用
  10. 深度学习之神经网络(二)
  11. OMNeT++下载、安装及实例tictoc1-tictoc18
  12. FTM的PWM、输入捕获、正交解码
  13. 使用R语言进行时间序列(arima,指数平滑)分析
  14. 程序是怎样跑起来的-读书文摘
  15. 什么是嵌入式?那嵌入式为什么用C语言?为什么不用其他语言?
  16. contentprovider与resolver使用
  17. apk protect下载地址
  18. potplayer最佳设置_PotPlayer调整常用设置让播放器效果更佳的具体操作流程
  19. 软键盘弹起后顶起EditText的完美解决方案
  20. Mac系统下docker容器无法使用--net host共享宿主机端口的解决方案

热门文章

  1. linux 用终端打开文件的方法
  2. java.io.UnsupportedEncodingException
  3. 微信小程序实现展开/收起的效果
  4. 技术改变生活 区块链正在改变你的生活方式
  5. 三分钟带您搞懂代理模式
  6. 知道什么时候该停下来!
  7. ASP.Net关于KindEditor编辑器的使用
  8. English Learning - Day13 作业打卡 2022.12.19 周一
  9. MySql主从复制(Master-Slave)
  10. 在红米K20 PRO上应用打开就闪退问题解决