算法 野人与传教士过河

问题描述:三个传教士和三个野人过河, 只有一条能装下两个人的船,在河的任何一方或者船上,野人的数量不能多于传教士的数量,如果野人的人数大于传教士的人数,那么传教士就会被吃掉。问采用何种渡河方法,可以安全过河,输出渡河的方式;

问题分析:
初始状态:船停靠在左岸
	左岸:3个传教士,3个野人;
	右岸:0个传教士,0个野人;
结束状态:船停靠在右岸
	左岸:0个传教士,0个野人;
	右岸:3个传教士,3个野人;

由于任何时刻野人的数量不能多于传教士的数量,所以一次渡河的方式如下:
1、渡一个传教士;
2、渡一个野人;
3、渡一个野人一个传教士;
4、渡两个传教士;
5、渡两个野人。

本算法可以通过状态空间法来求解,将渡河问题抽象成一系列状态的改变问题。
1、定义结构体,并定义结构体数组,用于存储状态结点信息;

2、编写状态空间函数:
1、判断当前状态是否与目标状态一致,若是,打印数组信息;
2、判断是否在遍历的过程中出现重复的渡河方式;
3、控制野人的数量与传教士的数量,使其满足(野人数<=传教士数);
4、写入全部渡河方式;

3、在主函数中给野人和传教士人数赋值,将值传给结构体数组,并调用状态空间函数检索渡河方法。

完整代码:

#include <stdio.h>
#define MAX 100
//状态节点定义
struct status
{
	int left_c;
	int right_c;
	int left_y;
	int right_y;
	int boat_location;
};
struct status arr[MAX];
int index=0;
int count=0;
int y_num=3,c_num=3;

int judge(status t);


void main()
{
	printf("\n...........检索开始..............\n");
	arr[index].left_c = y_num;
	arr[index].left_y = c_num;
	arr[index].right_c = 0;
	arr[index].right_y = 0;
	arr[index].boat_location = 1;
	judge(arr[index]);
	printf("已为您找到%d条过河路径!并且已全部加载完毕!\n",count);
}


int judge(status t)
{	
	if(	t.right_c == y_num && t.right_y == c_num)//判断当前状态是否达到目标转态
	{
		count++;
		printf("\n找到第%d条路径!\n",count);
		printf("左传\t左野\t右传\t右野\t船\n");
		for(int i = 0; i <= index ; i++)
		{
			printf("%2d\t",arr[i].left_c);
			printf("%2d\t",arr[i].left_y);
			printf("%2d\t",arr[i].right_c);
			printf("%2d\t",arr[i].right_y);
			printf("%2d\t",arr[i].boat_location);
			printf("\n");
		}
		return 0;
	}

	//判断有是否重复操作
	for(int i = 0; i < index; i++)
	{
		if(t.left_c == arr[i].left_c && t.left_y == arr[i].left_y)
		{
			if(t.boat_location == arr[i].boat_location)
			{
				return 0;
			}
			
		}
	}
	//人数是否合理吗
	if(t.left_c < 0 || t.left_y < 0 || t.right_c < 0 || t.right_y < 0  )
	{
		return 0;
	}
	//传教士是否被吃
	if((t.left_c < t.left_y && t.left_c != 0) || (t.right_c < t.right_y && t.right_c != 0) )
	{
		return 0;
	}

	//定义一个临时节点
	struct status tt;

	//一个传教士过河
	tt.left_c = t.left_c - 1 * t.boat_location;
	tt.left_y = t.left_y;
	tt.right_c = t.right_c + 1 * t.boat_location;
	tt.right_y = t.right_y;
	tt.boat_location = ( -t.boat_location);
	index = index + 1;
	arr[index] = tt;
	judge(arr[index]);
	index = index-1;

	//一个野人过河
	tt.left_c = t.left_c;
	tt.left_y = t.left_y - 1 * t.boat_location;
	tt.right_c = t.right_c;
	tt.right_y = t.right_y + 1 * t.boat_location;
	tt.boat_location = ( -t.boat_location);
	index = index + 1;
	arr[index] = tt;
	judge(arr[index]);
	index = index-1;


	//一个野人,一个传教士过河
	tt.left_c = t.left_c - 1 * t.boat_location;
	tt.left_y = t.left_y - 1 * t.boat_location;
	tt.right_c = t.right_c + 1 * t.boat_location;
	tt.right_y = t.right_y + 1 * t.boat_location;
	tt.boat_location = ( -t.boat_location);
	index = index + 1;
	arr[index] = tt;
	judge(arr[index]);
	index = index-1;
	
	//两个传教士过河
	tt.left_c = t.left_c - 2 * t.boat_location;
	tt.left_y = t.left_y;
	tt.right_c = t.right_c + 2 * t.boat_location;
	tt.right_y = t.right_y;
	tt.boat_location = ( -t.boat_location);
	index = index + 1;
	arr[index] = tt;
	judge(arr[index]);
	index = index - 1;
	
	//两个野人过河
	tt.left_c = t.left_c;
	tt.left_y = t.left_y - 2 * t.boat_location;
	tt.right_c = t.right_c ;
	tt.right_y = t.right_y + 2 * t.boat_location;
	tt.boat_location = ( -t.boat_location);
	index = index + 1;
	arr[index] = tt;
	judge(arr[index]);
	index = index-1;	

	return 0;
}


  • 3
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值