基于某盲目搜索算法求解泊松分酒韩信分油问题.docx
- 文档编号:24176802
- 上传时间:2023-05-25
- 格式:DOCX
- 页数:17
- 大小:65.42KB
基于某盲目搜索算法求解泊松分酒韩信分油问题.docx
《基于某盲目搜索算法求解泊松分酒韩信分油问题.docx》由会员分享,可在线阅读,更多相关《基于某盲目搜索算法求解泊松分酒韩信分油问题.docx(17页珍藏版)》请在冰豆网上搜索。
基于某盲目搜索算法求解泊松分酒韩信分油问题
题目:
基于盲目搜索算法求解泊松分酒问题
【摘要】
分酒问题的描述在历史上有很多版本,如泊松分酒、韩信分油等。
但是它们的本质都是相同的,无论是中间的转换过程中的各个杯子的容量,还是目标和初始的容量,都可以看作是网络中的一个节点。
而两种状态量之间是否可以进行转换可以看作是网络中两个节点是否连通。
由此原问题的是否可解、最少步数、多少种方式可以转化为网络中两个节点是否连通、最短路径、最短路径的条数的问题。
对于问题一,利用盲目搜索算法,由起始点出发进行搜索,如果找到了目标节点,则停止搜索,输出结果。
如果没有找到,则说明原问题不可解。
对于问题二,本文通过研究各个状态之间的转换关系,列写方程,通过判断方程是否有整数解来判定原问题是否可解。
并通过系数的求和来判断该解是否是最优解。
对于问题三,通过研究各个版本的分酒问题,发现史泰因豪斯在《数学万花筒》中的表述:
有装有14千克酒的容器,另外有可装5千克和9千克酒的容器,要把酒平分的问题即可满足要求。
并利用该问题对模型进行了检验。
最终,本文对于更大规模的分酒问题提出了自己的想法和改进思路,如利用模型二,首先剔除掉不连通的点,建立一个网络拓扑图,利用蚁群算法等智能算法,求解最短路问题,得到相对最优的解。
关键词:
泊松分酒盲目搜索不定方程蚁群算法
一、问题重述
分酒问题是一个十分著名的智力问题。
在历史上这个问题有很多版本:
泊松分酒、韩信分油等。
他们的原问题可以表述为三个容积不等的瓶子,如何实现将酒量等分。
显然这个问题的规模较小,可以通过人工来解决,然而当问题的规模变大,手工就变得无能为力了。
这就要求我们建立合适的模型来描述更大规模和一般性的问题,并利用合适的算法求解模型。
请尝试从基本问题出发建立数学模型解决以下问题:
问题一:
现有一只装满12斤酒的瓶子和三只分别装10斤、6斤和3斤酒的空瓶,如何才能将这12斤酒分成三等份。
如果进行四等份呢,结果如何?
如果4个瓶子分别要求装5斤、3斤、2斤、2斤,又能否实现?
试建立数学模型并设计算法,求最少经过多少步操作完成,且有多少种方式可采用最少步数完成。
要求对实现方式给出详细操作步骤。
问题二:
一般问题:
设有
个瓶子,每个瓶子最多装酒数量用向量表示为
。
现在初始各瓶子装酒为
。
现要实现将各瓶子装酒为
。
要求不凭借任何其它工具,问能否实现?
若能实现,给出实现的方法,并给出充分理由说明是否是最少步数。
并对你所使用的模型和算法进行分析说明。
问题三:
设计一个实例,要求最少完成步数不少于13步。
给出从初始状态到目标状态的详细实现步骤。
二、问题的分析
原问题有很多个版本:
版本1:
日本分油问题。
有一个装满油的8公升容器,另有一个5公升及3公升的空容器各一个,且三个容器都没有刻度,试将此8公升油分成4公升。
.
版本2:
法国著名数学家泊松年轻时研究过的一道题:
某人有12品脱美酒,想把一半赠人,但没有6品脱的容器,而只有一个8品脱和一个5品脱的容器,问怎样才能把6品脱的酒倒入8品脱的容器中。
版本3:
我国的韩信分油问题:
韩信遇到两个路人争执不下,原因是两人有装满10斤的油篓和两个3斤、7斤的空油篓,无法平均分出两份,每份5斤油。
韩信是如何解决这个难题的?
版本4:
史泰因豪斯在《数学万花筒》中的表述:
有装有14千克酒的容器,另外有可装5千克和9千克酒的容器,要把酒平分,该如何办?
版本5:
别莱利曼在《趣味几何学》中表述:
一只水桶,可装12杓水,还有两只空桶,容量分别为9杓和5杓,如何把大水桶的水分成两半?
虽然各个问题的表述不同,但是其本质之都是一样的。
解决这一类问题一般有三种方法:
作图法、尝试法和不定方程法。
文献[1]说明了三种手工求解的方法,这对于小规模问题可以解决,但是对于大规模问题就无能为力了。
文献[2][4]详细解释了如何用作图法解决该类问题,直观简洁。
文献[5][6]又介绍了如何用算法求解该问题,其中文献[6]是对文献[5]的一种改进。
本质上原问题的最优解就是状态量之间的最短路问题,问题是否可解就是两个不同状态直接是否联通的问题。
这样原问题就转换为一个网络拓扑的问题。
通过参考上述文献,针对问题一,本文采取盲目搜索算法,搜索各种可能的路径,一旦得到目标状态量,就停止搜索,这时得到的结果就是问题的最优解。
如果程序没有输出,则说明问题不可解。
对于问题二,本文利用不定方程组来初步判定问题是否可解。
问题三,通过试探,发现对于版本四问题的最小步数刚好13步,达到设计的要求。
三、基本假设
1、假设每次倒油的时候都没有油漏掉;
2、假设倒油时三个容器都不会将由留剩余容器壁上;
3、假设容器都没有损坏;
4、假设每次都是到空杯子或者将另一一个杯子倒满。
四、符号说明
符号
说明
第
个容器的最大容积
第
个容器的现存的容量
第
个容器向第
个容器倒入的次数
第
个容器的目标的容量
第
个容器的初始的容量
容器的个数
五、模型的建立与求解
5.1问题一模型的建立与求解
5.1.1模型的建立
问题一的模型较为简单。
酒瓶的初始状态
,最终的目标状态分别是
,
,
。
中间状态
的下一个状态最大可能有
种。
这样从初始状态开始搜索,直到搜索到目标状态,如果遍历所有可能状态都没有到达目标状态,说明初始状态与目标状态之间并没有联通。
遍历过程中对于已经遍历的节点不再遍历,降低算法的复杂度。
5.1.2模型的求解
由于每一个中间状态节点都最大有12不同的孩子节点,所以算法的整体数据结构为一个十二叉树。
对于每一个节点分别计算对应的12种情况,如果状态不存在,就将该节点接入树中。
如果已经存在,则不链接该节点,进行下一种情况的判断。
其中,树的建立要借助于队列这一个数据结构,借助其将每一个新节点入队、处理。
一旦发现目标状态节点,则停止循环,同时将目标节点以及其各个双亲节点入栈,直到初始状态节点。
最终再将各个节点出栈,出栈的顺序即为倒酒过程中,各个酒杯的酒量。
该十二叉树最底层叶子结点的个数即为可实现最短路径的方案个数。
运行程序得到结果分别为:
当目标状态为
其中一条最短路径为(12,0,0,0)->(2,10,0,0)->(2,4,6,0)->(2,1,6,3)->(8,1,0,3)->(11,1,0,0)->(1,10,0,1)->(1,4,6,1)->(1,4,4,3)->(4,4,4,0),
总共九步。
运行结果如下:
当目标状态为(3,3,3,3)时,其中的一条最短路径为(12,0,0,0)->(6,0,6,0)->(3,0,6,3)->(3,3,6,0)->(3,3,3,3),总共四步。
运行结果如下:
当目标状态为(5,3,2,2)时,没有得到结果说明,无法从初始状态到达目标状态。
5.2问题二模型的建立与求解
5.2.1模型的建立
分析可知,由于没有刻度,所以需要将杯子倒空或者将另一个杯子倒满。
所以每一次杯子内酒量的转换量都是各个杯子的容积或者他们的差值。
而且任何一个差值都可以由
的加权和来表示,即
,其中
为整数。
由此我们得到系数矩阵
(1)
其中
可以看作为第
杯向第
杯倒入的次数。
其中矩阵对角线上元素为0。
所以,第
杯中的剩余容量为
。
如果每一杯的剩余容量都等于目标容量,则说明问题可解。
函数方程为
(2)
如果方程有整数解,则说明原问题有解。
式中如果所有系数的和
较小,说明从初始状态到目标状态的最短步数相对较少。
具体的最短步数和最短路径可由第一问的算法解得。
5.2.2模型的说明
以日本分油问题为例,有一个装满油的8公升容器,另有一个5公升及3公升的空容器各一个,且三个容器都没有刻度,试将此8公升油分成4公升。
由于只有三个容器,问题的解可以转化为一个求解二元一次不定方程的解的过程。
方程为:
(3)
其中,
,
,
。
解得:
。
说明问题可解。
利用程序得到最短路径为(8,0,0)->(3,5,0)->(3,2,3)->(6,2,0)->(6,0,2)->(1,5,2)->(1,4,3)->(4,4,0),总共7步。
其中由大杯倒入中杯两次,小杯倒入大杯两次,与得到的系数一致。
5.3问题三模型的建立与求解
5.3.1模型的建立
通过试探,运用问题二的模型,发现版本4——史泰因豪斯在《数学万花筒》中的表述:
有装有14千克酒的容器,另外有可装5千克和9千克酒的容器,要把酒平分的问题最短路径刚好为13步。
其对应的不定方程为
(4)
最短路径为(14,0,0)->(5,9,0)->(5,4,5)->(10,4,0)->(10,0,4)->(1,9,4)->(1,8,5)->(6,8,0)->
(6,3,5)->(11,3,0)->(11,0,3)->(2,9,3)->(2,7,5)->(7,7,0)
六、模型的检验与结果分析
利用版本1~6的不同问题,对于模型所对应的程序进行了运行都得到了较好的结果,说明模型能够很好的适应这类小规模的问题,程序算法具有较好的适应性。
并且对所求最短路径进行检验,发现每条路径都是准确无误的。
七、模型的改进
虽然本模型对于上述问题得到了较好的结果,但是不难发现本质上都属于小规模问题。
如果问题的规模继续扩大,算法的空间复杂度和时间复杂度增长迅速,使得问题很难解决。
在这里本文提出两种改进方法:
1、可以首先将一些杯子合并成为一个系统,减少杯子的总量,先解决系统之间的问题,然后在解决系统内部的问题。
2、每一个问题的可能的状态总数是确定的,可以利用模型二,首先剔除掉不连通的点,建立一个网络拓扑图,利用蚁群算法等智能算法得到相对最优的解。
八、参考文献
[1]张安军.韩信立马分油问题的三种策略[J].中学数学杂志:
初中版,2016
(1).
[2]郭俊杰,毕双艳,雷冠丽.分油问题的网络最优化解法[J].吉林大学学报信息科学版,1989
(1):
33-38.
[3]任永胜.对“分油问题”的探微[J].山西师范大学学报(自然科学版),2014(s2):
32-34.
[4]彭世康,李春梅,彭金瑾.完整状态转移图法求三桶分油问题全部解[J].数学通报,2015
(1):
56-60.
[5]詹明清,詹横空.泊松分酒问题的一般解[J].电脑,1996(9)
[6]谭亮辉.再谈泊松分酒问题的解法[J].电脑,1997
(1)..
附录:
#include
#include
#include
#defineMethod12
#defineOK1
#defineTRUE1
#defineFLASE0
#defineERROR0
#defineINFESIBLE
#defineOVERFLOW-2
#defineSTACK_INIT_SIZE100
#defineSTACKINCREMENT10
#defineSElemTypepstate
#defineQUEUE_MAXSIZE500//最大队列长度
#defineQElemTypepstate
typedefstructstate{
intdata[4];
structstate*parent;
structstate*child[Method];
}state,*pstate;
typedefpstateSElemType;
typedefintStatus;
typedefstruct{
SElemType*base;
SElemType*top;
intstacksize;
}SqStack;
state*newState(state*parent,inta,intb,intc,intd)
{
state*pnew=(state*)malloc(sizeof(state));
pnew->parent=parent;
pnew->data[0]=a;
pnew->data[1]=b;
pnew->data[2]=c;
pnew->data[3]=d;
//pnew->pro=pro;
for(inti=0;i { pnew->child[i]=NULL; } returnpnew; } typedefstruct{ pstate*base;//队列的基址 intfront;//队首指针 intrear;//队尾指针 }SqQueue; StatusInitQueue(SqQueue&q)//初始化空循环队列q {q.base=(QElemType*)malloc(sizeof(QElemType)*QUEUE_MAXSIZE); //分配空间 if(! q.base)exit(OVERFLOW);//内存分配失败退出程序 q.front=q.rear=0;//置空队列 returnOK; }//InitQueue; StatusEnQueue(SqQueue&q,QElemTypee) {//向循环队列q的队尾加入一个元素e if((q.rear+1)%QUEUE_MAXSIZE==q.front) returnERROR;//队满则上溢,无法再入队 q.base[q.rear]=e;//新元素e入队 q.rear=(q.rear+1)%QUEUE_MAXSIZE;//指针后移 returnOK; }//EnQueue; StatusDeQueue(SqQueue&q,QElemType&e) {//若队列不空,删除循环队列q的队头元素, //由e返回其值,并返回OK if(q.front==q.rear)returnERROR;//队列空 e=q.base[q.front]; q.front=(q.front+1)%QUEUE_MAXSIZE; returnOK; }//DeQueue StatusInitStack(SqStack&S){ S.base=(SElemType*)malloc(STACK_INIT_SIZE*sizeof(SElemType)); if(! S.base) exit(OVERFLOW); S.top=S.base; S.stacksize=STACK_INIT_SIZE; returnOK; } StatusGetTop(SqStackS,SElemType&e){ //若栈不为空,则用e返回S的栈顶元素 if(S.top==S.base) returnERROR; e=*(S.top-1); returnOK; } StatusPush(SqStack&S,SElemTypee){ //插入元素e为新的栈顶元素 if(S.top-S.base>=S.stacksize){ S.base=(SElemType*)realloc\ (S.base,(S.stacksize+STACKINCREMENT)\ *sizeof(SElemType)); if(! S.base) exit(OVERFLOW); S.top=S.base+S.stacksize; S.stacksize+=STACKINCREMENT; } *S.top++=e; returnOK; } StatusPop(SqStack&S,SElemType&e){ //若栈不空,则删除S的栈顶元素并返回e if(S.top==S.base) returnERROR; e=*--S.top; returnOK; } Statusjudgeexist(inta,intb,intc,intd,intexistence[180][4],intexistsize){ inti; for(i=0;i if(existence[i][0]==a&&existence[i][1]==b&&existence[i][2]==c){ return1; } } return0; } Statusaddexist(inta,intb,intc,intd,intexistence[180][4],int&existsize){ existence[existsize][0]=a; existence[existsize][1]=b; existence[existsize][2]=c; existence[existsize][3]=d; existsize+=1; return0; } pstateBuildTree(pstateroot,intexistence[180][4],int&existsize,int*volume,int*last){ SqQueueQ; pstatee; inti,j,k,next,temp[4],changenum=0; InitQueue(Q); EnQueue(Q,root); while(Q.front! =Q.rear){ DeQueue(Q,e); changenum=0; next=0; for(i=0;i<4;i++) for(j=0;j<4;j++){ if(i! =j){ for(k=0;k<4;k++) temp[k]=0; temp[j]=(volume[j]-e->data[j]) (volume[j]-e->data[j]): e->data[i]; temp[i]=-temp[j]; if(temp[i]==0) continue; if(! judgeexist(e->data[0]+temp[0],e->data[1]+temp[1],e->data[2]+temp[2],e->data[3]+temp[3],existence,existsize)){ e->child[next]=newState(e,e->data[0]+temp[0],e->data[1]+temp[1],e->data[2]+temp[2],e->data[3]+temp[3]); addexist(e->data[0]+temp[0],e->data[1]+temp[1],e->data[2]+temp[2],e->data[3]+temp[3],existence,existsize); EnQueue(Q,e->child[next]); changenum++; if(judgeexist(last[0],last[1],last[2],last[3],existence,existsize)) returne->child[next]; next++; } } } } returnNULL; } Statusshow(pstatefinal){ pstatetemp; SqStacks; InitStack(s); temp=final; if(! final){ printf("没有可行解\n"); return0; } else{ while(temp){ Push(s,temp); temp=temp->parent; } while(s.base! =s.top){ Pop(s,temp); printf("(%d,%d,%d,%d)\n",temp->data[0],temp->data[1],temp->data[2],temp->data[3]); } } return0; } intmain(){ pstateroot,final; root=newState(NULL,13,0,0,0); intexistence[180][4]; intexistsize=0; intvolume[4]={16,14,6,3}; intlast[4]={6,5,2,0}; final=BuildTree(root,existence,existsize,volume,last); show(final); return0; }
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 基于 盲目 搜索 算法 求解 泊松分酒韩信分油 问题