连续邮资问题

article/2025/10/8 7:22:23

1、实验环境

Visual C++ 6.0

2、实验目的和要求

利用回溯法解决连续邮资问题。假设某国家发行了n种不同面值的邮票并且规定每张信封上最多只允许贴m张。对于给定的n和m的值,给出邮票面值的最佳设计,使得可在1张信封上贴出从邮资1开始,增量为1的最大连续邮资区间。

3、解题思路、伪代码

3.1解题思路

(1)对于连续邮资的问题,由于实验开始是仅给出面值的数量,而面值的具体值是未知的。但是由于邮资需要从1开始,因此,面值具体值中必然有1。可以建立一个数组用于存储具体的面值。X[1:n]表示从小到大存储具体面值。

(2)当面值为1时,可形成的连续邮资区间为1~m,在此基础上,若要增加面值,为保证区间连续,第二个面值必然要在2~m+1中取(第二个面值不能为1,并且若为m+2或者更大时,只用一个就变为m+2,此时不连续),第三个面值则需要根据前两个面值能达到的最大值来确定。第i个面值x[i]的连续区间若为1~r时,则第x[i+1]的个的取值必然为x[i]+1到r+1。则从第一个面值开始,接下来的各个面值的取值都由上一个面值以及能形成的最大值来取。

(3)但是为了求解最大连续区间,需要将面值的所有情况进行考虑,则对面值可能取值的语法树进行递归遍历,即回溯。递归到叶子节点时,将当前情况的最大值进行记录并与之前的进行比较,若更大则保存最大值,之后回溯到上一层继续求解,直到将所有情况计算完成。

(4)为在第n层得到最大连续邮资区间,则在前几层进行计算,必须要达到即保证连续,又要保证每个邮资值尽量使用比较少的邮票张数,即多使用邮资大的邮票。这就要求每引进一个新的邮票的时候,需要对当前邮资值数组进行更新,以保证每个邮资值的达到使用的是最少的邮票数。

回溯法按深度优先策略搜索问题的解空间树(问题的解空间树是虚拟的,并不需要在算法运行时构造一棵真正的树结构,只需要存储从根节点到当前节点的路径)。首先从根节点出发搜索解空间树,当算法搜索至解空间树的某一节点时,先利用剪枝函数判断该节点是否可行(即能得到问题的解)。如果不可行,则跳过对该节点为根的子树的搜索,逐层向其祖先节点回溯;否则,进入该子树,继续按深度优先策略搜索。回溯法的基本行为是搜索,搜索过程使用剪枝函数来为了避免无效的搜索。剪枝函数包括两类:

  1. 使用约束函数,剪去不满足约束条件的路径;
  2. 使用限界函数,剪去不能得到最优解的路径。

这种方法常常可以避免搜索所有可能的解,适用于求解组合数组较大的问题,在此问题中遍历确实可以得到问题的解,不过效率非常低,用回溯法可以有效地优化算法。

回溯法求解的三个步骤

1.针对问题,定义问题的解空间

2.确定容易搜索的解空间结构

3.以深度优先方式搜索解空间,并在搜索过程中用剪纸函数避免无效的搜索结果

3.2伪代码

#include<stdio.h>

#define maxl 1000    //表示最大连续值

#define maxint 32767

int n,m;      //n为邮票种类数,m为能贴的最大张数

int maxvalue;      //表示最大连续值

int bestx[100];     //表示最优解

int y[maxl];     //y[k],存储表示到k值,所使用的最少邮票数

int x[100];      //存储当前解

void backtrace(int i,int r);

int main(){

 printf("请输入邮票面值数:");

 scanf("%d",&n);

 printf("请输入能张贴邮票的最大张数:");

 scanf("%d",&m);

 for(int i=0;i<=n;i++){

  x[i]=0;

  bestx[i]=0;

 }

 for(int i=0;i<maxl;i++){

  y[i]=maxint;

 }

 x[1]=1;

 y[0]=0;

 maxvalue=0;

 backtrace(1,0);

 printf("当前最优解为:");

 for(int i=1;i<=n;i++){

  printf("%d ",bestx[i]);

 }

 printf("\n最大连续邮资为:");

 printf("%d",maxvalue);

 return 1;

}

void backtrace(int i,int r){

 for(int j=0;j<=x[i-1]*m;j++){    //对上一层的邮资值数组进行更新,上限是x[i-1]*m

  if(y[j]<m){

   for(int k=1;k<=m-y[j];k++){   //从只使用一个x[i]到使用m-y[i]个,即使用最多的最大值,降低邮票数

    if(y[j]+k<y[j+x[i]*k]){

     y[j+x[i]*k]=y[j]+k;   //如果前面的某一个情况加上k个x[i],所达到邮资值使用的邮票数少于原来的邮票数则更新

    }

   }

  }

 }

 while(y[r]<maxint){       //向后寻找最大邮资值

  r++;

 }

 if(i==n){         //i=n表示到达叶子节点。

  if(r-1>maxvalue){      //若大于最大值,则更新最优值与最优解

   for(int k=1;k<=n;k++){

    bestx[k]=x[k];    

   }

   maxvalue = r-1;

  }

  return;

 }

 int z[maxl];

 for(int k=0;k<maxl;k++){     //由于每一层需要对多种情况进行运算,因此需要将上一层的邮资值数组保留

  z[k] = y[k];

 }

 for(int j=x[i]+1;j<=r;j++){     //对下一层进行运算

  x[i+1]=j;

  backtrace(i+1,r-1);

  for(int k=0;k<maxl;k++)

   y[k]=z[k];

 }

}

4、实验步骤

4.1输入:

       2,3

       5,4

       4,3

4.2输出:

 

 

源码,取用点赞谢谢

#include<stdio.h>
#define maxl 1000    //表示最大连续值 
#define maxint 32767
int n,m;      //n为邮票种类数,m为能贴的最大张数 
int maxvalue;      //表示最大连续值
int bestx[100];     //表示最优解
int y[maxl];     //y[k],存储表示到k值,所使用的最少邮票数 
int x[100];      //存储当前解 
void backtrace(int i,int r);int main(){printf("请输入邮票面值数:");scanf("%d",&n);printf("请输入能张贴邮票的最大张数:");scanf("%d",&m);for(int i=0;i<=n;i++){x[i]=0;bestx[i]=0;} for(int i=0;i<maxl;i++){y[i]=maxint;}x[1]=1;y[0]=0;maxvalue=0;backtrace(1,0);printf("当前最优解为:");for(int i=1;i<=n;i++){printf("%d ",bestx[i]);} printf("\n最大连续邮资为:");printf("%d",maxvalue);return 1;
} void backtrace(int i,int r){for(int j=0;j<=x[i-1]*m;j++){    //对上一层的邮资值数组进行更新,上限是x[i-1]*m if(y[j]<m){for(int k=1;k<=m-y[j];k++){   //从只使用一个x[i]到使用m-y[i]个,即使用最多的最大值,降低邮票数 if(y[j]+k<y[j+x[i]*k]){y[j+x[i]*k]=y[j]+k;   //如果前面的某一个情况加上k个x[i],所达到邮资值使用的邮票数少于原来的邮票数则更新 }}}}while(y[r]<maxint){       //向后寻找最大邮资值 r++;}if(i==n){         //i=n表示到达叶子节点。 if(r-1>maxvalue){      //若大于最大值,则更新最优值与最优解 for(int k=1;k<=n;k++){bestx[k]=x[k];    }maxvalue = r-1;}return;}int z[maxl];for(int k=0;k<maxl;k++){     //由于每一层需要对多种情况进行运算,因此需要将上一层的邮资值数组保留 z[k] = y[k];}for(int j=x[i]+1;j<=r;j++){     //对下一层进行运算 x[i+1]=j;backtrace(i+1,r-1);for(int k=0;k<maxl;k++)y[k]=z[k];}
}

 


http://chatgpt.dhexx.cn/article/lMVjeFkQ.shtml

相关文章

寄信收信问题

问题 在一个村庄里有i个人&#xff0c;他们每个人只能寄出一封信&#xff0c;接收一封信&#xff0c;并且不能给自己寄信。那么请问一共有多少种寄信收信方式。 思路 遇到此类问题&#xff0c;应该从简单的情况考虑。比如&#xff0c;当村里只有两个人的时候&#xff0c;只有…

【图论】中国邮递员问题、平面图上最大割问题的多项式时间算法

文章目录 一、中国邮递员问题1. 与欧拉回路的关系2. Edmonds-Johnson算法3. 一个例子 二、平面图上的最大割问题1. 割2. 最大割及其 N P \bold{NP} NP完全性3. 平面图上的最大割问题4. 奇回路覆盖5. 转化为一般图最大匹配6. 一个例子 三、顶点图上最大割问题的 N P \bold{NP} N…

AMPL实现中国邮递员问题,你get到了吗

本文所有代码全部使用AMPL语言实现 中国邮递员问题和旅行商问题不太相同&#xff0c;旅行商问题是不能回头的&#xff0c;而邮递员问题要求是访问所有街道&#xff0c;也就是说每个街道必须访问到。 1、哥尼斯堡七桥问题 要解出中国邮递员问题&#xff0c;首先我们一起来了解…

关于中国邮递员问题和欧拉图应用

关于中国邮递员问题和欧拉图应用 中国邮递员问题&#xff1a; 1962年有管梅谷先生提出中国邮递员问题&#xff08;简称CPP&#xff09;。一个邮递员从邮局出发&#xff0c;要走完他所管辖的每一条街道&#xff0c;可重复走一条街道&#xff0c;然后返回邮局。任何选择一条尽可…

欧拉环游和中国邮递员问题

文章目录 前言欧拉环游Fleury算法中国邮递员问题 前言 这篇文章介绍了欧拉环游的定义判定&#xff0c;Fleury算法求欧拉图中的欧拉环游&#xff0c;最后给出了中国邮递员问题的解决步骤。 欧拉环游 所谓欧拉环游就是指在一个无向图中&#xff0c;从一个点出发&#xff0c;每…

中国邮递员问题最短路径(代码+实现)

奇点需要配合LINGO进行去除&#xff0c;有需要请联系1822285076qq.com&#xff0c;需要一定费用。 总程序&#xff1a; 奇点消除lingo代码&#xff1a;

一笔画问题(中国邮递员问题)

一笔画与中国邮递员问题 一、引述 一笔画问题&#xff1a; 节点可以重复走边不可以重复走要求把所有边都走一次 欧拉图(Euler graph)&#xff1a; 从任何节点开始&#xff0c;都可以一笔画 每一个节点都是偶数价&#xff08;价数指的是从该节点能够伸出去的边的数目&#x…

用遗传算法解决中国邮递员问题

中国邮递员问题 所谓中国邮递员问题&#xff0c;见下面无向图 &#xff0c;假设邮递员初始位置在A点&#xff0c;现在他要访问所有其他4个结点以便投递邮件&#xff0c;结点与结点之间的距离已经标注在边上。问&#xff1a;邮递员应该依次访问哪些结点才能以最短路径遍历所有结…

中国邮路问题邮递员问题欧拉路径图论C++

下载链接&#xff1a;https://download.csdn.net/download/RONNIE_Zz/13094843 通路&#xff1a;在无向图中由点边交替组成的序列就是通路&#xff08;如果这个图是简单的&#xff0c;那么也可以使用点的序列来表示&#xff09;&#xff0c;如果首尾的点相同&#xff0c;则称为…

邮局问题

原题&#xff1a;POJ 1160 题意&#xff1a; 一些村庄被建立在一条笔直的高速公路边上,我们用一条坐标轴来描述这条高速公路&#xff0c;每一个村庄的坐标都是整数&#xff0c;没有两个村庄坐标相同。两个村庄间的距离&#xff0c;定义为它们的坐标值差的绝对值。我们需要在一…

c语言邮递员问题算法,中国邮递员问题的求解实例

中国邮递员问题的求解实例 前面已经讲过&#xff0c;对于欧拉图&#xff0c;可以直接用Fleury算法找出一条欧拉巡回路线&#xff1b;对于半欧拉图&#xff0c;可以先求出奇点u和v之间的最短路径P,令G G P&#xff0c;贝U G *为欧拉图&#xff0c;然后用Fleury算法来确定一个G *…

ACM图论算法—邮递员投递问题

题目描述 著名图论问题之一。邮递员从邮局出发送信&#xff0c;要求对辖区内每条街&#xff0c;都至少通过一次&#xff0c;再回邮局。在此条件下&#xff0c;怎样选择一条最短路线&#xff1f;此问题由中国数学家管梅谷于1960年首先研究并给出算法&#xff0c;故名。 中国邮…

百子作业 —— 中国邮递员问题

题目 严老师和宋老板去勘测武威市区的道路网&#xff0c;每一条路都需要勘测&#xff0c;且需要两人合作.武威市区可以近似地看成六横六纵组成的道路网&#xff0c;自西向东依次为学府路、民勤路、西关路、中关路、富民路、滨河路&#xff1b;自北向南依次为雷海路、宣武路、祁…

邮递员算法问题之c++实现

目录 前言演示问题介绍思路代码复现尾言 前言 大家好&#xff0c;我是Ericam_。 近些时间&#xff0c;通过一个项目接触到了邮递员算法问题&#xff0c;还是挺有意思的&#xff08;虽然做起来经历了不少的困难&#xff09;。最后勉强复现了吧&#xff0c;写个文章就当记录一下。…

中国邮递员问题+代码实现(cpp)

中国邮递员问题是一个和旅行商问题比较相关但又不太相同的一个问题&#xff0c;而且个人感觉理解的难度更大一点&#xff0c;当然&#xff0c;这就是仁者见仁&#xff0c;智者见智了&#xff0c;旅行商问题是不能回头的&#xff0c;一个节点访问过了不能回来了&#xff0c;并不…

离散数学实验----中国邮递员问题

实验目的和要求 实验目的&#xff1a; 理解什么是欧拉图&#xff0c;熟悉欧拉路和欧拉回路的概念。掌握Dijkstra算法&#xff0c;求解最短路径掌握Fleury算法&#xff0c;求解欧拉回路。了解Edmonds-Johnson算法解决中国邮递员问题的基本思路。通过程序实现中国邮递员问题&…

数据结构——中国邮递员问题

问题描述 代码 #include <stdio.h> #include <stdlib.h> #include <string.h>#define min(a,b) ( (a) < (b) ? (a) : (b) ) #define MAX_NODE 100 #define MAX_EDGE 100 #define INF 0x7fffffff // 表示两点不连通typedef struct {int number; …

[算法导论] 邮递员问题

邮递员问题 旅行商问题&#xff1a;给定一系列城市和每对城市之间的距离&#xff0c;求解访问每一座城市一次并回到起始城市的最短回路。&#xff08;遍历点&#xff0c;回到起点&#xff09; 哈密顿路径 哈密顿图 中国邮递员问题&#xff1a;邮差要设法找到一条最短路径&…

中国邮递员问题的深入剖析与算法实现(附例题及MATLAB、LINGO代码)

中国邮递员问题的深入剖析与算法实现 一、研究背景1.1 哥尼斯堡七桥问题1.2 欧拉图1.3 中国邮递员问题 二、中国邮递员问题深入解读2.1 问题重述2.2 奇偶点图上作业法[^1]2.3 最小二分匹配法1) 针对无向图2) 针对有向图 2.4 $fleury$算法 三、经典中国邮递员问题的具体实现3.1 …

中国邮路算法(中国邮递员问题)(详细)

通路&#xff1a;在无向图中由点边交替组成的序列就是通路&#xff08;如果这个图是简单的&#xff0c;那么也可以使用点的序列来表示&#xff09;&#xff0c;如果首尾的点相同&#xff0c;则称为一条回路 无向图的连通性&#xff1a;无向图中任意一对点之间均有通路 欧拉通路…