农夫过河问题(回溯法)

问题描述:

一个农夫(人)过河问题,指在河东岸有一个农夫、一只狼、一只鸡和一袋谷子,只有当农夫在现场时狼不会把鸡吃掉,鸡也不会吃谷子,否则会出现吃掉的情况。另有一条小船,该船只能由农夫操作,且最多只能载农夫和另一样东西。设计一种过河方案,将农夫、狼、鸡和谷子借助小船运送到和西岸。

#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); //处理该条起始路径
}

运行结果:

在这里插入图片描述

  • 4
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值