野人过河问题

http://www.4399.com/flash/77287_2.htm

这是最基本的dfs方法 遍历所有情况

dfs过程中 只需要满足几个基本条件就可以

1. 传教士和野人数量都要在0~~3之间

2.传教士的数量一定要大于等于野人的数量

3.不可以走重复路线,避免构成循环,不可以回到起点的状态.


#include<iostream>
#include<cstdio>
#include<cstdlib>
using namespace std;




//岸的状态
typedef struct
{
	int wild_man;
	int church_man;

}RiverSide;

//船的状态
typedef struct
{
	int wild_man;
	int church_man;

}Boat;

//问题的目的是 将a岸的所有人运送到b岸  所以初始状态始 船在a岸
enum SIDE{ atA, atB };
//问题的状态
typedef struct ques
{
	RiverSide rA;
	RiverSide rB;

	SIDE Side;//该时刻 船所在的位置
	Boat boat;//船的状态

	struct ques *next;
	struct ques *pre;

}QUESTION;

QUESTION *start;
int SUM=0, sum=0;

Boat change[5] = { { 1, 0 }, { 0, 1 }, { 2, 0 }, { 0, 2 }, { 1, 1 } };

int state[100] = { 0 };
int Get_s(QUESTION *s)
{
	return s->Side * 16 + s->rA.church_man * 4 + s->rA.wild_man;
}


void ERROR(int i)
{
	if (i == 1)
	{
		cout << "fail malloc !" << endl; exit(1);
	}
}

void output_QUESTION(QUESTION *p)
{
	//船从*岸滑向~*岸(*牧师,*野人),此时a岸状态(*牧师,*野人),b岸状态(*牧师,*野人)
	++sum;
	cout << sum << ".";
	if (p->Side == atA)
		cout << "B--->A(" << p->boat.church_man << "牧师," << p->boat.wild_man << "野人),";
	else// p->side==atB
		cout << "A--->B(" << p->boat.church_man << "牧师," << p->boat.wild_man << "野人),";

	cout << "此时a岸状态(" << p->rA.church_man << "牧师," << p->rA.wild_man << "野人),b岸状态(" << p->rB.church_man << "牧师," << p->rB.wild_man << "野人)" << endl;

}

void output_route(QUESTION *t)
{
	++SUM;
	cout << "\n\n第"<<SUM<<"种方法:"<< endl;
	sum = 0;
	cout << "start pos:a岸状态(3牧师,3野人),b岸状态(0牧师,0野人)" << endl;
	t = t->next;
	while (t)
	{
		output_QUESTION(t);
		t = t->next;
	}
	cout << "let it go !~~~" << endl;
}
//for success
void success()
{
	output_route(start);
}
/*
dfs met:
1.任意时刻 :野人和 牧师 的 数量都要介于0~~3   牧师的数量要多余野人的数量
2.避免死循环 : 不和上一步走相同的路
*/

bool is_correct(QUESTION *t)
{
	//return (t->rA.church_man >= 0 && t->rA.church_man <= 3 && t->rA.wild_man >= 0 && t->rA.wild_man <= 3) && !state[Get_s(t)] && (t->rA.church_man==0 || (t->rA.church_man>=t->rA.wild_man)) &&( t->rB.church_man==0 ||( t->rB.church_man>=t->rB.wild_man ));
	return (t->rA.church_man >= 0 && t->rA.church_man <= 3 && t->rA.wild_man >= 0 && t->rA.wild_man <= 3) && !(t->rA.church_man==3 && t->rA.wild_man==3) && (t->rA.church_man == 0 || (t->rA.church_man >= t->rA.wild_man)) && (t->rB.church_man == 0 || (t->rB.church_man >= t->rB.wild_man));

}

void dfs(QUESTION *c)
{
	QUESTION *p;

	//for success
	if (c->rB.church_man == 3 && c->rB.wild_man == 3)
	{
		success();
		return;
	}

	//if (c->rA.church_man == 3 && c->rA.wild_man == 3 && !(c->boat.church_man == 0 && c->boat.wild_man == 0)) return;
	if (c->Side == atA)// 
	{//此时船从a(c点)走向b 新状态为船在b岸的状态(p点)
		for (int i = 0; i < 5; i++)
		{
			if (change[i].church_man == c->boat.church_man && change[i].wild_man == c->boat.wild_man)continue;

			p = (QUESTION *)malloc(sizeof(QUESTION));
			if (!p) { ERROR(1); }

			//for ra
			p->rA.church_man = c->rA.church_man - change[i].church_man;
			p->rA.wild_man = c->rA.wild_man - change[i].wild_man;

			//for rb
			p->rB.church_man = c->rB.church_man + change[i].church_man;
			p->rB.wild_man = c->rB.wild_man + change[i].wild_man;

			//for side
			p->Side = atB;

			//for change
			p->boat.church_man = change[i].church_man;
			p->boat.wild_man = change[i].wild_man;

			c->next = p;
			p->pre = c;

			p->next = NULL;

			if (is_correct(p))
			{
				//output_QUESTION(p);
				//state[Get_s(p)] = 1;
				dfs(p);

			}
			free(p);
			c->next = NULL;
		}
			//cout << "返回上一个节点" << endl << endl;

	}
	else   // c->Side=atB   //boat from b to a
	{
		for (int i = 0; i<5; i++)
		{
			if (change[i].church_man == c->boat.church_man && change[i].wild_man == c->boat.wild_man)continue;

			p = (QUESTION *)malloc(sizeof(QUESTION));
			if (!p) { ERROR(1); }

			//for ra
			p->rA.church_man = c->rA.church_man + change[i].church_man;
			p->rA.wild_man = c->rA.wild_man + change[i].wild_man;

			//for rb
			p->rB.church_man = c->rB.church_man - change[i].church_man;
			p->rB.wild_man = c->rB.wild_man - change[i].wild_man;

			//for side
			p->Side = atA;

			//for change
			p->boat.church_man = change[i].church_man;
			p->boat.wild_man = change[i].wild_man;

			c->next = p;
			p->pre = c;

			p->next = NULL;

			if (is_correct(p))
			{
				//output_QUESTION(p);
				//state[Get_s(p)] = 1;
				dfs(p);

			}

			free(p);
			c->next = NULL;
		}

		//cout << "返回上一个节点" << endl << endl;

	}


}


void solve()
{
	dfs(start);
}

int main()
{

	//for init start
	start = (QUESTION *)malloc(sizeof(QUESTION));
	if (!start) { ERROR(1); }


	start->rA.church_man = 3;
	start->rA.wild_man = 3;
	start->rB.church_man = 0;
	start->rB.wild_man = 0;

	start->Side = atA;

	start->boat.church_man = 0;
	start->boat.wild_man = 0;

	start->next = NULL;
	start->pre = NULL;
	//end for init
	state[Get_s(start)] = 1;

	//output_QUESTION(start);

	solve();

	return 0;
}







































  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
野人过河问题是一个经典的计算机算法问题,可以使用Java语言来解决。以下是一个简单的Java代码示例,用于解决三个传教士和三个野人的情况: ``` public class RiverCrossing { public static void main(String[] args) { int[] left = {3, 3, 1}; // 三个传教士,三个野人,一艘船在左岸 int[] right = {0, 0, 0}; // 右岸无人 crossRiver(left, right); } public static void crossRiver(int[] left, int[] right) { if (isFinished(left, right)) { // 如果所有人都已经到达右岸,输出结果 System.out.println("Solution found: "); System.out.println("Left: " + Arrays.toString(left)); System.out.println("Right: " + Arrays.toString(right)); return; } for (int i = 0; i < 3; i++) { // 遍历每个人 if (left[2] == 1 && left[i] == 1) { // 如果这个人在左岸且船在左岸 int[] newLeft = left.clone(); int[] newRight = right.clone(); newLeft[2] = 0; newLeft[i] = 0; newRight[2] = 1; newRight[i] = 1; if (isValid(newLeft) && isValid(newRight)) { // 如果移动后状态合法 crossRiver(newLeft, newRight); // 递归调用 } } } for (int i = 0; i < 3; i++) { // 遍历每个人 if (right[2] == 1 && right[i] == 1) { // 如果这个人在右岸且船在右岸 int[] newLeft = left.clone(); int[] newRight = right.clone(); newRight[2] = 0; newRight[i] = 0; newLeft[2] = 1; newLeft[i] = 1; if (isValid(newLeft) && isValid(newRight)) { // 如果移动后状态合法 crossRiver(newLeft, newRight); // 递归调用 } } } } public static boolean isValid(int[] state) { // 判断状态是否合法 if (state[0] < state[1] && state[0] > 0) { return false; } if (state[0] > state[1] && state[0] < 3) { return false; } return true; } public static boolean isFinished(int[] left, int[] right) { // 判断是否所有人都到达右岸 return left[0] == 0 && left[1] == 0 && left[2] == 0 && right[0] == 3 && right[1] == 3 && right[2] == 1; } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值