*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++