农夫过河问题-队列的应用
要模拟农夫过河问题,首先需要选择一个对问题中每个角色的位置进行描述的方法。一个很方便的办法是用四位二进制数顺序分别表示农夫,狼,白菜,和羊的位置。例如,用0表示农夫或者弄东西在河的南岸,1表示在河的北岸。因此,整数5(其二进制表示为1001)表示农夫和白菜在河的南岸,而狼和羊在北岸。这时农夫不在,因此狼可以把羊吃掉,所以是一种不安全的状态。问题的初始状态是整数0,;而问题的终结状态是整数15.
用整数location表示上述方法描述的状态,可以用下面的四个函数从上述状态中得到每个觉得所在的位置的代码。函数返回值为1表示所考察的人或物在河的北岸,否则在河的南岸。
队列的初始化:
#include "stdio.h" #include "stdlib.h" typedef int DataType; //队头f指出实队头元素所的位置,队尾r指出实队尾元素所的位置的下一个位置 struct SeqQueue { int MAXNUM; int f,r; DataType *q; }; typedef struct SeqQueue * PSeqQueue; //创建一个空队 PSeqQueue createEmptyQueue_seq(int m) { PSeqQueue paqu=(PSeqQueue)malloc(sizeof(struct SeqQueue)); if (paqu!=NULL) { paqu->q=(DataType *)malloc(sizeof(DataType) * m); if(paqu->q) { paqu->MAXNUM=m; paqu->f=0; paqu->r=0; return paqu; } else { free(paqu); } } printf("out of space!! \n"); return NULL; } //判断paqu所指的队列是否为空队列 int isEmptyQueue_seq(PSeqQueue paqu) { return (paqu->f==paqu->r); } //入队运算,为环形队列 void enQueue_seq(PSeqQueue paqu,DataType x) { if ((paqu->r+1)% paqu->MAXNUM==paqu->f) { printf("Full queue. \n"); } else { paqu->q[paqu->r]=x; paqu->r=(paqu->r+1)%paqu->MAXNUM; } } //出队 void deQueue_seq(PSeqQueue paqu) { if (paqu->f == paqu->r) { printf("Empty Queue. \n"); } else { paqu->f=(paqu->f+1)%paqu->MAXNUM; } } //取队列的头元素 DataType frontQueue_seq(PSeqQueue paqu) { if (paqu->f == paqu->r) { printf("Empty Queue. \n"); } else { return (paqu->q[paqu->f]); } }
//个体状态判断函数 //判断农夫的位置 int farmer(int location) { return (0!=(location & 0x08)); } //判断狼的位置 int wolf(int location) { return (0!=(location & 0x04)); } //判断白菜的位置 int cabbage(int location) { return (0!=(location & 0x02)); } //判断羊的位置 int goat(int location) { return (0!=(location & 0x01)); }
//安全状态判断函数,若安全则返回1; int safe(int location) { if (goat(location)==cabbage(location) && goat(location)!=farmer(location)) { return 0; } if (goat(location)==wolf(location) && goat(location)!=farmer(location)) { return 0; } return 1; }
void farmerProblem() { int i,movers,location,newLocation; //用于记录已考虑的状态路径 int route[16]; //用于记录可以安全到达的中间状态 PSeqQueue moveTo; //创建空队列 moveTo=createEmptyQueue_seq(16); //初始状态进队列 enQueue_seq(moveTo,0x00); //准备数组route的初值 for(i=0;i<16;i++) { route[i]=-1; } route[0]=0; while (!isEmptyQueue_seq(moveTo)&&(route[15]==-1)) { location=frontQueue_seq(moveTo); deQueue_seq(moveTo); for(movers=1;movers<=8;movers<<=1) { //农夫和移动的物品在同一岸 if ((0!=(location & 0x08))==(0!=(location & movers))) { //计算新状态 newLocation=location^(0x08|movers); } //新状态安全且未处理 if (safe(newLocation) && (route[newLocation]==-1)) { //记录新状态的前驱 route[newLocation]=location; //新状态入队 enQueue_seq(moveTo,newLocation); } } } //打印路径 //到达最终状态 if (route[15!=-1]) { printf("The reverse path is: \n"); for(location=15;location>=0;location=route[location]) { printf("The location is : %d \n",location); if (location==0) { exit(0); } } } else { printf("No solution \n"); } }
int main(int argv,char * argm[]) { farmerProblem(); return 1; }
结果: