商人过河问题.docx

上传人:b****4 文档编号:26987382 上传时间:2023-06-24 格式:DOCX 页数:25 大小:28.43KB
下载 相关 举报
商人过河问题.docx_第1页
第1页 / 共25页
商人过河问题.docx_第2页
第2页 / 共25页
商人过河问题.docx_第3页
第3页 / 共25页
商人过河问题.docx_第4页
第4页 / 共25页
商人过河问题.docx_第5页
第5页 / 共25页
点击查看更多>>
下载资源
资源描述

商人过河问题.docx

《商人过河问题.docx》由会员分享,可在线阅读,更多相关《商人过河问题.docx(25页珍藏版)》请在冰豆网上搜索。

商人过河问题.docx

商人过河问题

商人过河问题  

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

 *M个商人与每人各带的一个仆人过河问题

 *船每次至多运N个人,至少要有一人划船

 *在任一岸,当商人数<仆人数时,仆人就杀人越货

 *过河由商人安排运送人员及数目

 *找出安全渡河的全部方法并打印(原问题中M=3,N=2)

 *2010-10-1020时许(纪念伟大的双十)

 *LYP

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

 

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

 *本题为多步决策

 *若考虑只针对人数为 M=3 对,每次过河人数最多 N=2

 *可以证明路径中必须经坐标中(3,1)过至(1,1)点(过诃时),

 *后返回至(2,2)点,再过诃至(0,2)点(只剩2个仆人)

 *可以先考虑(3,3)到(3,1)点

 *再经(0,2)至(0,0),完成过诃(由图形的对称性关系,可以直接将(3,1)至(3,1)路径翻转,更改对应标号即可)

 *当然也可以用动态规划求解

 *本代码不限定M,N值,可通过修改宏M,N的值,求其他商人(仆人)数与最大过河人数的全部路径

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

 

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

 *

 *商人数x< 仆人数y时遭杀人越货,过河失败

 *对应可行域为:

 *x=0,y=0…M;       elements[]中编号0…M

 *0

 *x=M,y=0…M;   elements[]中编号2M…3M

 *图像上表示如下:

(共 3*M+1 个点),过河即从3M点到0点

 *过河为左下方1/4圆区域

 *返回为右上方1/4圆区域

 *点成中心对称分布,对称的点过河、返回时点的分布情况互为相同

 

 /\ y:

仆人

 |

 |                                               编号:

M*                     *                   M\     \3M 

 |                        |                    .

 *            *         *                  .

 *       *             *                   2\M+2\2M+2

 *   *                 *                   1\M+1\2M+1

-*------------------*-------->     0\      \2M

 |0                      M           x:

商人

 |

 *

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

 

 

#include

#include

#include

 

#defineM3

/*M为商人仆人对数*/

#defineN2

/*N为渡河时船的最大容量*/

#defineSTACK_Vol30

/* 栈的容量*/

#defineDEBUG0

/* 调试时用的宏,用于查看unit中可到达的各点编号*/

 

enumstatus{NO,YES};

/* 标记elements中的go_flag(back_flag)*/

/* 以NO=0标记过河(返回)时没到过该点,YES=1标记过河(返回)到过该点*/

 

structElement{

       int*         go;                        /* 存储过河时可以到达的点的动态空间指针,以-1标记结束*/

       int*         back;                    /* 存储返回时可以到达的点的动态空间指针,以-1标记结束*/

       enumstatus    go_flag;          /* 以NO=0标记为未曾从该点过河,YES=1为曾从该点过河*/

       enumstatus    back_flag;       /* 以NO=0标记为未曾从该点返回,YES=1为曾从该点返回*/

}elements[3*M+1];

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

 *对可行域的点对行编号,全局变量,已被自动初始化为NULL和0

 *考虑到N一般较小,每点到达的点也较少,所以进行初始化并存储在动态分配的空间中

 *只考虑较小的N,对较大的N(>=4),解题为平凡的,程序空间时间复杂度较大,不用本程序求解

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

 

structStack{

       intarray[STACK_Vol+1];   /* 存储经过的路径,注意:

最多为30步*/

       intmark[STACK_Vol+1];   /* 存储经过对应点的链表中下次要走的元素标号*/

       inttop;                                /* 栈顶指针,指向使用的空间*/

}stack;

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

 * 找出路径要用到的运算栈 *

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

 

 

intpath_ok;                                /* 记录找到路径数量*/

intup_bound=3*M;                 /* 数组中最大点的下标(上界*/

 

voidunit(void);                          /* 初始化各点的可到达的点*/

voidpath(void);                         /* 找出无环路的过河路径*/

voidprint_path(int*);          /* 打印出过河的路径*/

voiddelete_link(void);          /* 释放动态分配的内存*/

 

intmain()

{

       clock_tstart,finish;

       doubleduration;                   /* 测量一个事件持续的时间*/

       start=clock();                     /* 取初始时刻时间*/

 

       unit();

       path();

       if(path_ok<1)

              printf(" 没有可行路径!

!

!

\n");

       delete_link();

 

       finish=clock();                   /* 取完成时刻时间*/

       duration=(double)(finish-start)/CLOCKS_PER_SEC;

       printf("\n\nProgrammeExecuteTime:

\t%.3fseconds\n",duration);

 

       getchar();

       return0;

}

 

 

voidunit(void)

{

       int*p1,*p2;

       inthead,rear;

       intvert,level,diag,sum;       /* 记录垂直、水平、斜向方向上所能到的点的个数*/

       inti;                                    /* 循环变量*/

 

       /*0为目标点,不进行初始化*/

       /*up_bound为出发点,只考虑过河情况*/

       level=N-M;

     /*level<0,商人无法全部过河;

      *=0,商人刚好全部过河,后只能从M点原样返回(无其他返回点),所以不考虑该点;

      * >0,商人全部过河外可以有仆人过河*/

       vert=M>N?

N:

M;

       diag=N>>1;

       if(level<0)

              level=0;

       sum=vert+diag+level+1;

       if(sum>1){

              elements[up_bound].go=p1=(int*)malloc(sum*sizeof(int));

              for(i=1;i<=level;i++)

                     *p1++=M-i;

              for(i=1;i<=vert;i++)

                     *p1++=up_bound-i;

              for(i=1;i<=diag;i++)

                     *p1++=(M<<1)-i;

              *p1=-1;

       }//if

 

       for(head=1,rear=up_bound-1;head

              /* 先计算head过河时的情况:

只有仆人过河;对应的rear为返回时的情况:

只商人返回*/

              vert=head>N?

N:

head;

              sum=vert+1;

              if(sum>1){

                     elements[head].go  =p1=(int*)malloc(sum*sizeof(int));

                     elements[rear].back=p2=(int*)malloc(sum*sizeof(int));

                     if(p1==NULL||p2==NULL){

                            fprintf(stderr," 动态分配内存失败!

\n\n");

                            delete_link();

                            exit(EXIT_FAILURE);

                     }//if

                     for(i=1;i<=vert;i++){

                            *p1++=head-i;

                            *p2++=rear+i;

                     }//for(i)

                     *p1=*p2=-1;

              }//if

 

              /* 再计算head返回时的情况*/

              /* 只仆人返回*/

              vert=M-head;

              if(vert>N)

                     vert=N;

              /* 商人返回一个或全部时的情况*/

              if(N>=M){                              /* 商人可以全部返回*/

                     level=2+N-M;

                            if(head+N-M>M)

                                   level=2+M-head;

              }

              elseif(N>=head)

                     level=1;

              else

                     level=0;

 

              /* 仆人商人返回至等数量,但不包括开始时的情况*/

              diag=(N-head)>>1;

              if(diag<0)

                     diag=0;

              elseif(head+diag>=M)

                            diag=M-head-1;

              sum=vert+level+diag+1;

              if(sum>1){

                     elements[head].back      =p1=(int*)malloc(sum*sizeof(int));

                     elements[rear].go   =p2=(int*)malloc(sum*sizeof(int));

                     if(p1==NULL||p2==NULL){

                            fprintf(stderr," 动态分配内存失败!

\n\n");

                            delete_link();

                            exit(EXIT_FAILURE);

                     }//if

                     for(i=1;i<=vert;i++){

                            *p1++=head+i;

                            *p2++=rear-i;

                     }

                     if(level==1){

                            *p1++=head+M;

                            *p2++=rear-M;

                     }

                     elseif(level>1){

                            *p1++=head+M;

                            *p2++=rear-M;

                            vert=(M<<1)-1;                           /* 临时挪用存储数值*/

                            for(i=1;i

                                   *p1++=head+vert+i;

                                   *p2++=rear-vert-i;

                            }

                     }

                     for(i=1;i<=diag;i++){

                            *p1++=head+M+i;

                            *p2++=rear-M-i;

                     }

                     *p1=*p2=-1;

              }//if

       }//for(head)

       /* 单独计算 head=M 的情况*/

       /* 返回时,head=M的点只能返回出发点(且只可能从出发点过河到此点)。

       * 同理,rear=2M点只可能过河到目标点0,但只有从目标点0可以返回到2M点,所以不用考虑*/

       vert=N>=M?

M:

N;               /*只计算过河情况*/

       sum=vert+1;

       if(sum>1){

              elements[head].go  =p1=(int*)malloc(sum*sizeof(int));

              elements[rear].back       =p2=(int*)malloc(sum*sizeof(int));

              if(p1==NULL||p2==NULL){

                     fprintf(stderr," 动态分配内存失败!

\n\n");

                     delete_link();

                     exit(EXIT_FAILURE);

              }//if

              for(i=1;i<=vert;i++){

                     *p1++=head-i;

                     *p2++=rear+i;

              }//for(i)

              *p1=*p2=-1;

       }//if

 

       head++,rear--;                                   /* 准备下次的点*/

       for(;head

              /* 先算返回情况*/

              /* 商人全部返回*/

              level=head+N-(M<<1);

              if(level<0)

                     level=-1;

              elseif(head-M+level>M)

                     level=(M<<1)-head;

              level++;

              /* 等量返回时*/

              diag=N>>1;

              if(head+diag>=(M<<1))

                     diag=(M<<1)-head-1;

              sum=level+diag+1;

              if(sum>1){

                     elements[head].back      =p1=(int*)malloc(sum*sizeof(int));

                     elements[rear].go   =p2=(int*)malloc(sum*sizeof(int));

                     if(p1==NULL||p2==NULL){

                            fprintf(stderr," 动态分配内存失败!

\n\n");

                            delete_link();

                            exit(EXIT_FAILURE);

                     }//if

                     for(i=0;i

                            *p1++=head+M+i;

                            *p2++=rear-M-i;

                     }

                     for(i=1;i<=diag;i++){

                            *p1++=head+i;

                            *p2++

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 高等教育 > 理学

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1