野人过河问题(一)

//--------- 野人过河问题(一) -------------

//Missionaries.cpp:Defines the entry point for the console application.

//注:去掉#include <stdafx.h>,一般除MFC工程外,都不使用预编译头。
//#include "stdafx.h"

/*
实验原理:假设开始时传教士、野人和船都在右岸,用数组(a,b,c)分别表示右岸传教士个数、右岸野人个数、船的位置,
  则可分为三种情况讨论:
  A、 n>m/2。此种情况下,先把所有的野人渡过去,每次返回一个野人,当出现(m,0,0)情况时,返回m-n个野人(若m==n,返回1个
  野人)。然后渡n个传教士,此时野人==传教士,然后返回一个野人和传教士,再开始最大限度的渡传教士,每次返回一个人,最终知道a==b==c==0;
  B、n<=3 && n<=m/2 || n==1,显然此时无解;
  C、n>=3 && n<=m/2,此时只能每次传n/2个传教士和野人,每次返回一个野人和传教士,直到最终结果。
  初始状态是s(m,m,1)---最终状态是s(0,0,0)
*/
#include "iostream"
using namespace std;

bool flag = false; //标记是否有解
bool af = false; //标记a是否为0
bool bf = false; //当b变为0后赋值为true;
bool ef = false; //当a==b后赋值为true
bool  f = false; //判断n是否大于m/2
int   m; //传教士野人的个数
int   n; //船一次能装载的人数

void crossing(int a,int b,int c);

int main()
{
	cout<<"传教士与野人过河问题。\n假设最初时传教士与野人在河的右岸。\n";
	cout<<"请输入传教士野人的个数:\n";
	cin>>m;
	cout<<"请输入船一次能装载的个数:\n";
	cin>>n;
	cout<<"右岸传教士个数\t"<<"右岸野人个数\t"<<"船的位置(1、右岸 0、左岸)"<<endl;
	
	if((n<=3 && n<=m/2) || n==1)//此种情况无解
	{
		cout<<"No solution!\n";
		system("pause"); //请按任意键继续
		return 0;
	}

	if(n > m/2)
	{
		f = true;
	}
	//调用函数
	crossing(m,m,1);
	if(flag == true)
	{
		cout<<"Success!\n";
	}
	else
	{
		cout<<"No solution!\n";
	}
	system("pause");
	return 0;
}

void crossing(int a,int b,int c)
{
	if(flag == true)
	{
		return;
	}
	else
	{
		if(c == 1)//船在右岸时:
		{
			cout<<"\t"<<a<<"\t\t"<<b<<"\t\t"<<c<<"\t\n";
			//如果n>m/2
			if(f == true)
			{
				if(bf!=true) //b未达到过0 b!=0
				{
					if(a+b<=n) //如果a+b<=n,完全渡过
					{
						crossing(0,0,1-c); //递归
					}
					else
					{
						for(int j = n; j >= 0; j--)
						{
							if(b >= j) //野人数大于或等于船的载量
							{
								crossing(a,b-j,1-c); //递归
								if(flag==true)
									return;
							}
						}
					}
				}
				else if(ef!=true && af == false) //b!=0 && a!=0
				{
					for(int i = n; i >= 0; i--)
					{
						if(a >= i)
						{
							crossing(a-i,b,1-c); //递归
							if(flag == true)
							{
								return;
							}
						}
					}
				}

				if(ef == true && af ==false) //a==b && a!=0
				{
					if(a>=n)
					{
						crossing(a-n,b,1-c); //递归
					}
					//如果a<n时
					else if(a+b<n)
					{
						crossing(0,0,1-c);
					}
					else
					{
						crossing(0,b-(n-a),1-c);
					}
				}
				if(af == true)//a==0
				{
					if(b>=n)
					{
						crossing(a,b-n,1-c); //递归
					}
					else
					{
						crossing(a,0,1-c);
					}
				}
			}
			//n<=m/2
			else
			{
				crossing(a-n/2,b-n/2,1-c); //递归
			}
		}

		//船在左岸时,右岸的情况
		if( c == 0)
		{
			cout<<"\t"<<a<<"\t\t"<<b<<"\t\t"<<c<<"\t\n";
			if(a == b && b == c && a == 0)
			{
				flag = true;
				return;
			}
			if(f == true) //如果n>m/2
			{
				if( b == 0 )
				{
					bf = true;
					if(m <= n)
						crossing(a,b+1,1-c); //递归
					else
						crossing(a,b+m-n,1-c);
				}

				if(a == b)
				{
					ef = true;
					crossing(a+1,b+1,1-c); //递归

				}
				if(a == 0)
				{
					af = true;
					crossing(a,b+1,1-c); //递归
				}
				while(bf!=true)
				{
					crossing(a,b+1,1-c); //递归
				}
			}
			else //n<=m/2
				crossing(a+1,b+1,1-c); //递归
		}
	}
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值