人样狼草过河数学建模

  • 格式:doc
  • 大小:84.00 KB
  • 文档页数:8
queue[rear]=Status; rear=(rear+1)%16;//入队
while(front!=rear){
Status=queue[front];front=(front+1)%16;//出队
visited[Status]=1; //访问
for(j=0;j<4;j++){
nextStatus=Status^choice[j]; //从curStatus状态到下一状态nextStatus
人然后是B状态,B状态表示用船渡河过程中表示船内运载的状况,当一物在船上时用1表示,不再船上则用0表示,当满足问题条件的运载称为可取运载,当不满足条件的运载则是不可取运载,如B1(1,1,0,0)表示人狼崽船上,但它不是可取状态,同样B2(1,0,1,1)也不是可取状态,应为船不能载三物。
我们可以通过穷举法得到可取状态向量:
(7)1 (1 , 1 ,0 , 0 )=(1,0,0,1 ) !
(0,1,0,1 ) + (1, 0, 1, 0)=(1,1,1,1) +
(1, 0 , 0 , 1)=(1,1,0,0) !
(1 , 0 ,0 ,0 )=(1,1,0,1) *
取(1,0,1,1)计算:
(4)2 (1 , 1 ,0 , 0 )=(0,1,1,1) !
三解法
1.穷举法
注:在得到的状态后面的标示符中,“!”表示该状态不可取,“+”表示该状态可取,“*”表示该状态已经出现过,为重复状态。
(1)(1,1,0,0)=(1,1,0,0)!
(0,0,0,0) +(1,0,1,0)=(1,0,1,0)+
(1,0,0,1)=(1,0,0,1)!
(1, 0, 0, 0) =(1,0,0,0)!
建模
状态转移方程:原状态㈩运载=现状态
一可取状态向量㈩可取运载向量,称之为过河。
其中㈩运算方式为“1+1=0,1+0=1,0+1=1,0+0=0”。
二、模型
在规则“1+1=0,1+0=1,0+1=1,0+0=0”下,
试求从最初可取状态向量(0,0,0,0)经过N步到最终状态向量(1,1,1,1)的可取转移方式。
课程设计报告
课程名称:数学建模
设计题目:人狼羊草过河问题
姓名学号:马高松()
易文辉()
陈邦生()
指导老师:李沐春
完成时间:2010年5月8日
问题的提出
在河的一岸,人、狼、羊、草、均要过河,船需人划,而且最多载一物,当人不在时,狼会吃羊,羊会吃草;试安排人狼羊草安全渡河。
一问题的分析
人带着狼、羊和草,身处河的一岸。他要把这些东西全部运到彼岸。问题是他面前只有一条小船,船小到只能容下他和一件物品,另外船必须有人划。而且,因为狼能吃羊,而羊爱吃草,所以人不能留下羊和草或者狼和羊单独在河的一边。以下是解决方案:
return 1;//1表示安全,0表示不安全
}
//过河,使用广度优深算法遍历
int crossRiver(int result[]){
int Status,nextStatus,choice[]={8,9,10,12};//农夫从某一状态出发,有4种走法
int queue[16],front,rear;//定义循环队列
(1, 0 , 0 , 1)=(1,0,0,0) !
(1 , 0 ,0 ,0 )=(1,0,0,1) !
得到的可取状态和(5)1步骤一样,故运算(6)2、(7)2应该和(6)1、(7)1一样。所以总共可以通过七步运算使得人、狼、羊、草安全过河。
2.图解法
四、算法实现
1.问题分析
完成了上面的准备工作,要模拟农夫过河问题,首先需要选择一个对问题中每个角色的位置进行描述的方法。一个很方便的办法是用四位二进制数顺序分别表示人狼羊草的位置。例如用0表示人或者某物在河的南岸,1表示在河的北岸。因此整数3(其二进制表示为0011)表示人和狼在河的南岸,而羊和草在河的北岸。
整个过程中我们把该过程分为两种状态A和B,在各状态中,将人羊狼草用一个四维向量表示,A状态表示人羊狼草在河的左右岸的状态,当一物在左岸时,用分量0表示,当一物在右岸时,用分量1表示,例如状态A1(1,1,0,1)表示人羊草在河的右岸,狼崽河左岸,根据题中的要求,有些状态时允许的,有些状态是不允许的,这就牵涉到该方案的安全性,于是我们规定由条件允许存在的状态我们称之为可取状态,比如A1(0,1,0,1)是一个可取状态,而A2(0,0,1,1)则是一个不可取状态,因为他表示羊草在河的右岸,是不可取的;
for(i=0,j=0;j<16;j++){
if(result[j]>=0){
cout<<"第"<<i<<"步:\t"<<name[result[j]]<<endl;
现在的问题变成:
从初始状态二进制0000(全部在河的南岸)出发,寻找一种全部由安全状态构成的状态序列,它以二进制1111(全部到达河的北岸)为最终目标,并且在序列中的每一个状态都可以从前一状态通过人(可以带一样东西)划船过河的动作到达。
2.算法选择
求解这个问题的最简单的方法是一步一步进行试探,每一步都搜索所有可能的选择,对前一步合适的选择再考虑下一步的各种方案。
五、程序代码
#include<iostream>
using namespace std;
int man(int n){
return (0!=(n & 8));//判断农夫在不在,如果返回1,则表示农夫在。
}
int wolf(int n){
return (0!=(n & 4));
}
int sheep(int n){
if(visited[nextStatus]==0 && isSafe(nextStatus)){
queue[rear]=nextStatus; rear=(rear+1)%16;//入队
route[nextStatus]=Status;//仅表示从Sattus可以走到nextStatus
//如route[10]=0,意即从0000有路可走到1010
(0,0 ,1,0 ) + (1, 0, 1, 0)=(1,0,0,0) !
(1, 0 , 0 , 1)=(1,0,1,1) +
(1 , 0 ,0 ,0 )=(1,0,1,0) *
第三步中得到的结果有两个可取状态,故应分别计算
先取(1,1,1,0)计算:
(4)1 (1 , 1 ,0 , 0 )=(0,0,1,0) *
广度优先的含义就是在搜索过程中总是首先搜索下面一步的所有可能状态,然后再进一步考虑更后面的各种情况。
要实现广度优先搜索,一般都采用队列作为辅助结构。把下一步所有可能达到的状态都列举出来,放在这个队列中,然后顺序取出来分别进行处理,处理过程中把再下一步的状态放在队列里。由于队列的操作遵循先进先出的原则,在这个处理过程中,只有在前一步的所有情况都处理完后,才能开始后面一步各情况的处理。
}
}
}
//处理路径表:从路径表中反推(从最终步-->开始步)
i=15;//最后一步
if(route[i]==-1) { //若没有方法可以走到1111,则任务失败。
cout<<"过河失败!"<<endl;
return 0;
}
for(j=15;route[i]!=-1 && i>=0;j--){ //route[i]!=-1相当于那一步走不通,那就不用选取了
1人不在时: 三个全不在的 (1,1,1,1)
两个不在的 (1,1,1,0)、(1,1,0,1)、(1,0,1,1)
一个不在的 (1,0,1,0)
② 人在时: 三个全在的 (0,0,0,0)
一个不在的 (0,0,0,1)、(0,0,1,0)、(0,1,0,0)
两个不在的 (0,1,0,1)
一共有10种状态。
(1,1 ,1,0 ) +(1, 0, 1, 0)=(0,1,0,0) +
(1, 0 , 0 , 1)=(0,1,1,1) !
(1 , 0 ,0 ,0 )=(0,1,1,0) !
(5)1 (1 , 1 ,0 , 0 )=(1,0,0,0) !
(0,1,0,0 ) +(1, 0, 1, 0)=(1,1,1,0) *
深度优先搜索亦称为纵向搜索。由于一个有解的问题树可能含有无穷分枝,深度优先搜索如果误入无穷分枝(即深度无限),则不可能找到目标节点。所以,深度优先搜索策略是不完备的。另外,应用此策略得到的解不一定是最佳解(最短路径)。
深度优先搜索算法中,是深度越大的结点越先得到扩展。如果在搜索中把算法改为按结点的层次进行搜索,本层的结点没有搜索处理完时,不能对下层结点进行处理,即深度越小的结点越先得到扩展,也就是说先产生的结点先得以扩展处理,这种搜索算法称为广度优先搜索法。
"人狼草\t\t\t羊", "人狼\t\t\t羊草",
"人羊草\t\t\t狼", "人羊\t\t\t狼草",
"人草\t\t\t狼羊", "人\t\t\t狼羊草",
"狼羊草\t\t人", "狼羊\t\t\t人草",
"狼草\t\t\t人羊", "狼\t\t\t人羊草",
"羊草\t\t\t人狼", "羊\t\t\t人狼草",