传教士(牧师)与野人问题-模拟人工智能实验

题目:

有n个牧师和n个野人准备渡河,但只有一条能容纳c个人的小船,为了防止野人侵犯牧师,要求无论在何处,牧师的人数不得少于野人的人数(除非牧师人数为0),且假定野人与牧师都会划船,试设计一个算法,确定他们能否渡过河去,若能,则给出小船来回次数最少的最佳方案。

实验步骤:

输入:牧师人数(即野人人数):n;小船一次最多载人量:c。
输出:若问题无解,则显示Failed,否则,显示Successed输出所有可行方案,并标注哪一组是最佳方案。用三元组(X1, X2, X3)表示渡河过程中的状态。并用箭头连接相邻状态以表示迁移过程:初始状态->中间状态->目标状态。
例:当输入n=2,c=2时,输出:221->200->211->010->021->000;
其中:X1表示起始岸上的牧师人数;X2表示起始岸上的野人人数;X3表示小船现在位置(1表示起始岸,0表示目的岸)。
要求:写出算法的设计思想和源程序,并有用户界面实现人机交互(控制台或者窗口都可以),进行输入和输出结果,如:
Please input n: 2 Please input c: 2
Optimal Procedure: 221->200->211->010->021->000
Successed or Failed?: Successed

实现代码:

#include<stdio.h>
#include<iostream>
#include<stdlib.h>
using namespace std;
struct State {
	int Lsavage;
	int Lgodfather;
	int Rsavage;
	int Rgodfather;
	int boat;                  //boat at left = 0 ; boat at right =1;
};
struct State *States = new State[150];
struct routesave {
	int savage;
	int godfather;
};
struct routesave* routesaves = new routesave[150];
int godfather, savage, boatnum;

void init(State &m) {
	cout << "请输入野人和牧师的人数n, 以及船的最大载量c"<<endl;
	int n, c;
	cin >> n >> c;
	m.Rgodfather = n;
	m.Rsavage = n;
	godfather = n, savage = n;
	boatnum = c;
	m.Lgodfather = m.Lsavage = 0;
	m.boat = 1;
}

void boaloading(int i, int s, int g) {        //s个野人和g个传教士
	if (States[i].boat == 0) {
		routesaves[i].savage = s*-1;                  //左边到右边是负数个野人
		routesaves[i].godfather = g * -1;              //左边到右边负数个传教士
		States[i + 1].Lsavage = States[i].Lsavage - s;
		States[i + 1].Lgodfather = States[i].Lgodfather - g;
		States[i + 1].Rsavage = States[i].Rsavage +  s;
		States[i + 1].Rgodfather = States[i].Rgodfather + g;
		States[i + 1].boat = 1;
	}
	else {
		routesaves[i].savage = s;                  //右边到左边是正数个野人
		routesaves[i].godfather = g;               //右边到左边正数个传教士
		States[i + 1].Rsavage = States[i].Rsavage-s;
		States[i + 1].Rgodfather = States[i].Rgodfather - g;
		States[i + 1].Lsavage = States[i].Lsavage + s;
		States[i + 1].Lgodfather = States[i].Lgodfather + g;
		States[i + 1].boat = 0;
	}
}

bool checkState(State m) {
	if (m.Rgodfather > 0 && m.Rgodfather < m.Rsavage)
		return false;
	if (m.Lgodfather > 0 && m.Lgodfather < m.Lsavage)
		return false;
	else return true;
}

void showSolution(int i) {
	cout << "问题解决,解决路径为:"<<endl;
	for (int c = 0; c < i; c++) {
		if (routesaves[c].savage >= 0)
			cout << "第" << c+1 << "步," << routesaves[c].savage << "个野人和" << routesaves[c].godfather << "个传教士乘船去左边" << endl;
		else 
			cout << "第" << c+1 << "步," << routesaves[c].savage * -1 << "个野人和" << routesaves[c].godfather * -1 << "个传教士乘船去有右边"<< endl;	
	}
}

void nextstep(int i) {
	int c;
	if (i >= 150)
	{
		cout <<"试探路径过大,无法计算";
		exit(0);
	}
	for (c = 0; c < i; c++) /*if the current state is same to previous,retrospect*/
	{
		if (States[c].Lsavage == States[i].Lsavage && States[c].Lgodfather == States[i].Lgodfather && States[c].Rsavage == States[i].Rsavage && States[c].Rgodfather == States[i].Rgodfather && States[c].boat == States[i].boat)
		{
			goto a;
		}
	}
	if (States[i].Rsavage == 0 && States[i].Rgodfather == 0 && States[i].boat == 0) {
		showSolution(i);
		exit(0);
	}

	if (States[i].boat == 1) {              //船在右边
		for (int s = 1; s <= boatnum && s<=States[i].Rsavage; s++) {//g=0
			int g = 0;
			boaloading(i, s, g);
			if (checkState(States[i+1])) {
				nextstep(i+1);			
			}		
		}
		for (int g = 1; g <= boatnum && g<=States[i].Rgodfather; g++) {   //g!=0
			for (int s = 0; s <= boatnum - g && s<=States[i].Rsavage && s<=g; s++) {
				boaloading(i, s, g);
				if (checkState(States[i + 1])) {
					nextstep(i + 1);
				}
			}
		
		}
	
	}

	if (States[i].boat == 0) {              //船在左边
		for (int s = 1; s <= boatnum && s <= States[i].Lsavage; s++) {//g=0
			int g = 0;
			boaloading(i, s, g);
			if (checkState(States[i + 1])) {
				nextstep(i + 1);
			}
		}
		for (int g = 1; g <= boatnum && g <= States[i].Lgodfather; g++) {   //g!=0
			for (int s = 0; s <= boatnum - g && s <= States[i].Lsavage && s <= g; s++) {
				boaloading(i, s, g);
				if (checkState(States[i + 1])) {
					nextstep(i + 1);
				}
			}

		}
	
	}
a:return;
}

void main() {
	init(States[0]);
	nextstep(0);
}

实验结果展示:在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

  • 10
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值