问题描述:
一个农夫(人)过河问题,指在河东岸有一个农夫、一只狼、一只鸡和一袋谷子,只有当农夫在现场时狼不会把鸡吃掉,鸡也不会吃谷子,否则会出现吃掉的情况。另有一条小船,该船只能由农夫操作,且最多只能载农夫和另一样东西。设计一种过河方案,将农夫、狼、鸡和谷子借助小船运送到和西岸。
#include<stdio.h>
int FamerLocation(int state) //判断农夫的位置
{
return (state & 0x08)!=0;
}
int WolfLocation(int state) //判断狼的位置
{
return (state & 0x04)!=0;
}
int ChickenLocation(int state) //判断鸡的位置
{
return (state & 0x02)!=0;
}
int RiceLocation(int state) //判断谷子的位置
{
return (state & 0x01)!=0;
}
int IfSafe(int state) //判断当前状态是否安全
{ //安全返回1,不安全返回0
if (FamerLocation(state)!= WolfLocation(state) && WolfLocation(state)== ChickenLocation(state)) //当农夫和狼位置不同而狼和鸡位置相同时不安全
{
return 0;
}
else if ((FamerLocation(state)!= ChickenLocation(state)) && (ChickenLocation(state)==RiceLocation(state))) //当农夫和鸡位置不同而鸡和谷子位置相同时不安全
{
return 0;
}
else
{
return 1;
}
}
void Process(int route[16],int state) //算法核心,输入要处理的路径route[16]和该路径当前最新位置state
{
if (route[15]==-1) //如果该路径还未到达目的状态
{
int which;
for (which=1;which<= 8;which *= 2) //依次带不同的动物或单独过河过河4种方案
{
if (((state & 0x08)!=0)==((state & which)!=0)) //如果农夫和要带的动或物在同一侧
{
int nextLocation = state ^ (0x08 | which); //用异或运算表示出过河后的状态,异或代表把船上的(0x08|which)从一岸移动到另一岸;(0x08|which)代表船上有农夫和which代表的东西
if (IfSafe(nextLocation) && route[nextLocation]==-1) //状态回溯法:判断下一个状态是否安全并且是否产生重复(剪枝)
{
int nextRoute[16];
for (int i=0;i<16;i++) //用一个新的数组先拷贝当前的路径
{
nextRoute[i]=route[i];
}
nextRoute[nextLocation]=state; //然后再记录下这新的一步
Process(nextRoute,nextLocation); //用递归(深度优先搜索)再以同样方式处理这个新的路径和最新位置
}
}
}
}
else //该路径到达了目标状态
{
int location = 15;
while (location!=-2)
{
printf("%d ",location);
switch(location){
case 0:printf("农夫、狼、鸡、谷子都没有过河\n");break;
case 1:printf("农夫驾船带鸡从河西岸返回到东岸\n");break;
case 2:printf("农夫单独从河西岸返回到东岸\n");break;
case 4:printf("农夫驾船带鸡从河西岸返回到东岸\n");break;
case 5:printf("农夫单独从河西岸返回到东岸\n");break;
case 10:printf("农夫驾船带鸡从河东岸到西岸\n");break;
case 11:printf("农夫驾船带谷子从河东岸到西岸\n");break;
case 13:printf("农夫驾船带谷子从河东岸到西岸\n");break;
case 14:printf("农夫驾船带狼从河东岸到西岸\n");break;
case 15:printf("农夫驾船带鸡从河东岸到西岸\n");break;
}
location=route[location];
printf("\n");
}
printf("\n");
printf("-----------------------------------\n");
}
}
int main()
{
int route[16];
for (int i=1;i<16;i++) //初始化路径,未经历的状态记录-1
{
route[i]=-1;
}
route[0]=-2; //起始状态已经经历过且没有前驱节点记录为-2
Process(route,0); //处理该条起始路径
}
运行结果: