数学建模:研究商人过河问题

玛丽莲梦兔
762次浏览
2021年02月23日 09:29
最佳经验
本文由作者推荐

-

2021年2月23日发(作者:短跑冠军)

























数学建模实验一报告




实验题目:


研究商人过河问题



一、实验目的:


编写一个程序(可以是


C,C ++



Mathlab


)实现商人安全 过河


问题。



二、实验环境:


Turbo c 2.0



Microsoft Visual C++ 6.0



Matlab 6.0


以上




三、实验要求:


要求该程序不仅能找出一组安全过河的可行方案,还可以得

< p>
到所有的安全过河可行方案。


并且该程序具有一定的可扩展性,

< p>
即不仅可以实现


3


个商人,


3


个随从的过河问题。还应能实现



n


个商人,


n


个随从的过河问题以及< /p>


n


个不同对象且每个对象有


m

< p>
个元素问题


(



明:


对于


3


个商人,


3


个随从问题分别对应于


n=2,m=3)


的过河问题。


从而给出课


后习题


5< /p>



n=4,m=1


)的全部安全过河方案 。








四、实验步骤:






第一步:问题分析。这是一个多步 决策过程,涉及到每一次船上的人员以及


要考虑此岸和彼岸上剩余的商人数和随从数,< /p>


在安全的条件下


(两岸的随从数不


比商人 多)


,经有限步使全体人员过河。






第二步:


分析模型的构成。


记第


k


次渡河前此岸 的商人数为


x


k


随从数为


y


k


< br>k



1


,


2




x


k


,


y


k



1


,


2



n



(具有可扩展性)


,将


定义为状态,状态集合



x


k


,


y


k

< p>



x


,


y



|


x


0


,


y



0


,


1


,< /p>


2


,


3


;


x



3


,

< p>
y



0


,


1


,


2


,

3


;


x



y



1


,


2< /p>


}


成为允许状态集合(


S




S={


记第


k


次渡船的商人数为


u


k< /p>


,随从数为


v


k


,决策为


(


u


k


,


v


k


)


, 安全渡河条件下,








< br>许















D






u


,


v



|


1

< br>


u



v



2


,


u


,


v



0


,


1


,


2


|1


因为


k


为奇数时船从此岸


D={


驶向彼岸,


k


为偶数时船由彼岸驶向此岸,所以状态


s

k


随决策


d


k

变化的规律是


s


k



1



s


k

< br>


(



1


)


d


k


k


, 此式为状态转移律。制定安全渡河方案归结为如下的多步决


策模型:求决策


d


k



D

< br>(


k



1


,


2



n


)


,使状态


s


k



S


按照转移律,由初始状态


s


1



(


3

< p>
,


3


)


经有限

< p>
n


步到达


s


n

< p>


1



(


0


,


0


)


第三步:模型求解。



#include




#include


#include


#include


#include


using namespace std;


#include


FILE *fp;/*


设立文件指针,以便将它用于其他函数中


*/


struct a{


long m,s;


struct a *next;


};/*

< br>数组类型


a


:记录各种情况下船上的商人和仆人数,


m


:代表商人数



s


:代表仆人数


*/


struct a *jj,head;/*head


为头指针 的链表单元(船上的人数的各种情况的链表)


*/


int n ,total=0,js=0;/*total


表示船上各种情况总数

< br>*/


struct aim {


long m1,s1,m2,s2;


int n;


struct


aim


*back,*next;};/*

< br>用于建立双向的指针链表,记入符合的情况,


m1



s1


表示要过岸


的商人数和仆人数;


m2



s2


表示过岸 了的商人数和仆人数,


n


表示来回的次数


*/


int k1,k2;


void freeit(struct aim *p){


struct aim *p1=p;













p1=p->back;


free(p);


if(p1!=NULL)


p1->next=NULL;


return;


}/*


释放该单元格 ,并将其上的单元格的


next


指针还原


*/




int determ(struct aim *p)


{ struct aim *p1=p;


if(p->s1>k2)return -1;/*


仆人数不能超过总仆人数


*/


if(p->m1>k1)return -1;/*


商人数不能超过总商人数


*/


if(p->s2>k2)return -1;/*


对岸,同上


*/


if(p->m2>k1)return -1;/*


对岸,同上


*/


if(p->s1<0)return -1;/*


仆人数不能为负


*/


if(p->s2<0)return -1;/*


商人数不能为负


*/


if(p->m1<0)return -1;/*


对岸,同上


*/


if(p->m2<0)return -1;/*


对岸,同上


*/


if(p->m1!=0)


if(p->s1>p->m1)return -1;


if(p->m2!=0)


if(p->s2>p->m2)return -1;/*


两岸商人数均不能小于仆人数


*/


while(p1!=NULL){




p1=p1->back;


if(p1!=NULL)


if(p1->n%2==p->n%2)


if(p1->s1==p->s1)


if(p1->s2==p->s2)


if(p1->m1==p->m1)


if(p1->m2==p->m2)


return -1; }/*


用于解决重复,算法思想:即将每次算出的链表单元与以前的相比较,若重复,< /p>


则表示出现循环


*/


if(p->s1==0&&p->m1==0)


if(p->n%2==0)return 1;


else return -1;/*


显然如果达到条件就说明


ok



*/


return 0;}/*


判断函数


*/


int sign(int n){


if(n%2==0)return -1;


return 1;}/*


符号函数


*/


void copyit(struct aim *p3,struct aim *p){


p3->s1=p->s1;


p3->s2=p->s2;


p3->m1=p->m1;


p3->m2=p->m2;


p3->n=p->n+1;


p3->back=p;


p3->next=NULL;


p->next=p3;



}/*


复制内容函数,将

< p>
p


中的内容写入


p3


所指 向的链表单元中


*/


void print(struct aim *p3){


struct aim *p=p3;


js++;


while(p->back){p=p->back;}


p rintf(



%d


种方法

< p>
:n


fprintf(fp,


< br>%d


种方法


:n


int count=0;


while(p){ printf(


fprintf(fp,


p=p->next;


count++;


}


cout<<


一共有



步完成



}/*


打印函数,将


p3


所指的内容打印出来


*/



void trans(struct aim *p){


struct aim *p3;/*p3


为申请的结构体指针


*/




struct a *fla;


int i,j,f;


fla=&head;


p3=(struct aim *)malloc(sizeof(struct aim));


f=sign(p->n);


for(i=0;i


fla=fla->next;


copyit(p3,p);


p3->s1-=fla->m*f;


p3->m1-=fla->s*f;


p3->s2+=fla->m*f;


p3->m2+=fl a->s*f;/*


运算过程,即过河过程


*/


j=determ(p3);/*


判断,


j


记录判断结果


*/


if(j==-1){


if(i


else{


freeit(p3);


break;}}


int count1=0;


if(j==1){if(i


count1++;



continue;}


else{print(p3);


freeit(p3);


break;}


//cout<


printf(


printf(


}


if(j==0)trans(p3);


}


return;


}/*


转移函数,即将人转移过河


*/


/*n=0*/



void main()


{ struct aim *p,*p1;int j,a,e,f;


struct a *flag;/*flag


是用与记录头指针


*/


FILE*fpt;


if((fpt=fopen(


printf(


exit(0);}


fp=fpt;



system(





printf(


问题描述:三个商人 各带一个随从乘船过河,一只小船只能容纳


X


人,由他们自己< /p>


划船。


三个商人窃听到随从们密谋,


在河 的任意一岸上,


只要随从的人数比上人多,就杀掉


商人。但是如 何乘船渡河的决策权在商人手里,商人们如何安排渡河计划确保自身安全?


n

< p>


printf(





p=(struct aim *)malloc(sizeof(struct aim));


p->back=NULL;


p->next=NULL;


p->s2=0;


p->m2=0;


p->n=1;/*


设立初始头指针


*/

< br>printf(


fprintf(fp,


请输入船上的人 数


n


scanf(


fprintf(f p,


flag=&head;


for(e=0;e<=n;e++)



for(f=0;f<=n;f++)



if(e+f>0&&e+f<=n)



{ total++;



jj=(struct a*)malloc(sizeof(struct a));



jj->m=e;



jj->s=f;



flag->next=jj;



jj->next=NULL;



flag=jj;



}



/*********************************/


printf(


fprintf(fp,


sc anf(


fprintf(fp,


/************ **********************/


k1=p->m1;


k2=p->s1;


trans(p);


fclose(fpt);


getch();


}


第一步:三个商人,三个随从的模型求解答案为:



运行后的结果为:





1


种方案:


(3,3)




(0,0)



(3,1)




(0,2)



(3,2)




(0,1)



(3,0)




(0,3)



(3,1)




(0,2)



-


-


-


-


-


-


-


-