连续邮资问题的解决办法

连续邮资问题
                                             ------策划方案
1、问题描述
       假设国家发行了n种不同面值的邮票,并且规定每张信封上最多只允许贴m张邮票。连续邮资问题要求对于给定的n和m的值,给出邮票面值的最佳设计,在1张信封上可贴出从邮资1开始,增量为1的最大连续邮资区间。
2.解决方案及基本思想(递归)
  (1)基本思路:
           搜索所有可行解,当i<=n时,当前结点Z是解空间中的内部结点。在该结点处x[1:i-1]能贴出最大连续区间为r-1。因此,在结点Z处,x
的可能取值范围是[x[i-1]+1:r],从而,结点Z有r-x[i-1]个儿子结点。算法对当前结点Z的每一个儿子结点以深度优先遍历的方式递归的对应子树进行搜索,从而找出最大连续邮资区间的方案。
  (2)解向量:
           用n元组x[1:n]表示n种不同的邮票面值,并约定它们从小到大排列。x[1]=1是唯一的选择。(x
表第i张邮票的面值)
  (3)可行性约束函数:
           已选定x[1:i-1],最大连续邮资区间是1—r-1,下来x
的可取值范围是x[i-1]+1—r。(r-1表x[1:i-1]所能达到的连续区间的上界)
  (4)如何确定r的值:
           计算x[1:i]的最大连续邮资区间在本算法中被频繁使用到,因此势必要找到一个高效的方法。考虑到直接递归的求解复杂度太高,用不超过m张面值为x[1:i]的邮票贴出邮资k所需的最少邮票数y[k]。通过y[k]可以很快推出r的值。具体算法如下:
    for (j=0; j<= x[i-2]*(m-1);j++)
         if(y[j]<m)
           for (k=1;k<=m-y[j];k++)
             if (y[j]+k<y[j+x[i-1]*k]) y[j+x[i-1]*k]=y[j]+k;
   while (y[r]<MAXNUM) r++;
  在初始化y[]是都把它赋值为MAXNUM(y[0]=0),其中MAXNUM表足够大的整数。
3.核心算法
      在该算法核心的算法是如何求最大连续区间r-1的值
   for (j=0; j<= x[i-2]*(m-1);j++)
        if(y[j]<m)
          for (k=1;k<=m-y[j];k++)
            if (y[j]+k<y[j+x[i-1]*k]) y[j+x[i-1]*k]=y[j]+k;
  while (y[r]<MAXNUM) r++;
  在初始化y[]是都把它赋值为MAXNUM(y[0]=0),其中MAXNUM表足够大的整数。
4.初步模块
   InitStamp(*S, nn, mm){
     //给S赋初值。
     //其中S为指向Stamp类型的指针变量,nn为邮票的种数,mm为最多贴邮票的张数。
    }
  BackTrack(*S,i,r){
     //递归回溯,求出前i种邮票所能达到的最大连续区间1¬-r-1
    }
   OutPut(S){
     //输出maxvalue和*bestx
    }
   main(){
//调用上述模块,解决连续邮资问题。
}
  各模块之间的调用关系如下:
     InitStamp(*S, nn, mm){
•••
BackTrack(*S,2,1);
•••
}
           BackTrack(*S,i,r){
•••
BackTrack(*S,i+1,r+1);
•••
}
main(){
•••
InitStamp(*S, nn, mm);
OutPut(S);
}
5、数据结构
   typedef struct{
     int  n,              //邮票面值数                  
         m,              //贴邮票最多数
         maxvalue;        //当前最优解
     int *bestx;            //当前最优解
     int *x;               //当前解
     int *y;               //贴出各种邮资所需最少邮票数
    }Stamp;
6、测试数据
   当n=5和m=4时,面值为(1,3,11,15,32)的5种邮票可以贴出邮资的最大连续邮资区间是1到70。
  

 

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值