数据结构 第7章 修道士 实验报告
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
数据结构
实验报告第七章
实验名称:修道士野人问题
实验类型:综合性实验
班级:
学号:
姓名:
实验日期:2014年5月21日
1.问题描述
河的左岸有N个野人和N个修道士以及一条小船,修道士们想用这条小船把所有的人都运到河的右岸,但又受到以下限制:
●修道士和野人都会划船,但船一次只能载C人。
●在任何岸边,为了防止野人侵犯修道士,野人数不能超过修道士数,否
则修道士将会被野人吃掉。
假定野人愿意服从任何一种过河的安排,本设计的主要任务是规划出一种确保修道士安全的过河方案。
2.数据结构设计
用一个三元组(num1,num2,an)表示渡河过程中的各个状态。num1表示左岸上修道士的个数,num2表示左岸上野人的个数,an表示小船位置(0-在右岸上,1-在左岸上)。定义一个结构体,用于存放各个时刻的状态:
typedef struct
{
int num1;//修道士人数
int num2;//野蛮人人数
int an;//表示两岸,0在右岸,1在左岸
}DataType;
用邻接表存储结构实现图的操作,其存储结构为:
typedef struct Node
{
int dest; //邻接表的弧头结点序号
struct Node *next;
}Edge; //邻接表单链表的结点结构体
typedef struct
{
DataType data; //结点数据元素
int sorce; //邻接表的弧尾结点序号
Edge *adj; //邻接边的头指针
int pre; //指向此点的点的序号
}AdjLHeight; //数组的数据元素类型结构体
typedef struct
{
AdjLHeight a[10000]; //邻接表数组
int numOfVerts; /结点个数
int numOfEdges; //边个数
}AdjLGraph; //邻接表结构体
3.算法设计
一侧的野人数目和修道士数目以及船在哪一岸共同构成一种状态,分析一会发现合法的状态是有限且固定的。此时这个问题的求解便类似于寻路问题,已知两个结点和所有节点间的连接关系,求两结点之间的一条路径,简单地进行广度优先搜索即可。
根据给出的小船上的位置数量,生成小船上的安全状态,即在船上的时候修道士的人数也要比野人的数量要多(除非修道士人数为0)。渡船优先规则:左岸一次运走的人越多越好(即左岸运多人优先),同时野人优先运走;右岸一次运走的人越少越好(即右岸运少人优先),同时修道士优先运走。
类似于操作系统中的银行家算法的安全性检测,即让修道士跟野人上船后,检测当船到达对岸后,两岸修道士的安全状态,若修道士安全,则将此结点加入到邻接表中。
采用广度优先搜索,得到一条通路将其输出即可。
部分关键程序:
int findfa(DataType x) //生成在船上修道士仍安全的情况
{
int i=0,a,b,t=0;//从始案到末岸的状态
if(x.an)
{
a=0;b=c-a;
while (a+b>=1)
{
t++;
while (b>=0)
{
fa[i].num1=a;
fa[i].num2=b;
i++;
a++;
b--;
}
a=0;
b=c-a-t;
}
}
else//从末岸到始岸的状态
{
a=1;b=0;t=0;
while (a+b<=c)
{
t++;
while (a>=0)
{
fa[i].num1=a*(-1);
fa[i].num2=b*(-1);
i++;
a--;
b++;
}
a=fa[0].num1*(-1)+t;
b=0;
}
}
return i;
}
int print(AdjLGraph *p,int g) //打印安全渡河的过程
{
DataType b[1000];
int i=0;
while (g!=-1)
{
b[i++]=p->a[g].data;
g=p->a[g].pre;
}
while ((--i)>-1)
{
printf("( %d %d %d )",b[i].num1,b[i].num2,b[i].an);
if (!(b[i].num1==0&&b[i].num2==0&&b[i].an==0))
{
if (b[i].an==1)
printf(" 船上人数[修道士,野人][%d %d] 右边岸上[%d %d
0]\n",b[i].num1-b[i-1].num1,b[i].num2-b[i-1].num2,b[i-1].num1,b[i-1].num2);
else
printf(" 船上人数[修道士,野人][%d %d] 左边岸上[%d %d 1]\n",(b[i].num1-b[i-1].num1)*(-1),(-1)*(b[i].num2-b[i-1].num2),b[i-1].num1,b[i-1].n um2);
}
else
printf("\n");
}
printf("\n");
return 1;
}
void work(AdjLGraph *p) //广度搜索建立表
{
DataType tem;
int i,flag1,g=0,j,count=0,k=0,t;
while (p->a[k].data.an!=-1)
{
j=findfa(p->a[k].data);
for (i=0;i { tem.num1=p->a[k].data.num1-fa[i].num1; tem.num2=p->a[k].data.num2-fa[i].num2; tem.an=1-p->a[k].data.an; if (check(tem)) { flag1=1; t=k; while (t!=-1) { if(tem.num1==p->a[t].data.num1&&tem.num2==p->a[t].data.num2&&tem.an== p->a[t].data.an) { flag1=0; break; } t--; } if(flag1==1) { g++;