使用深度优先搜索解决传教士野人(MC)问题

使用深度优先搜索解决传教士野人(MC)问题

深度优先搜索算法步骤:

  1. 把初始节点S0放入OPEN表。
  2. 如果OPEN表为空,则问题无解,退出。
  3. 把OPEN表的第一个节点(记为节点n)取出放入CLOSE表。
  4. 考察节点n是否为目标节点。若是,则求得了问题的解,退出。
  5. 若节点n不可扩展,则转第2步。
  6. 扩展节点n,将其子节点放入OPEN表的首部,并为每一个子节点都配置指向父节点的指针,然后转第2步。
#include  <iostream>
#include<vector>
#include <algorithm>
using namespace std;
//定义状态
class bank {
public:
	int MissionaryNum;
	int CannibalsNum;
	int BoatInHere;
	int FatherPoint;//存放父节点在close表中的下标
	int OrderNumber;//从初始到当前节点的代价
	bool operator==(bank bank1);
};
bool bank::operator==(bank bank1)
{
	if (this->BoatInHere == bank1.BoatInHere
		&& this->CannibalsNum == bank1.CannibalsNum
		&& this->MissionaryNum == bank1.MissionaryNum)
	{
		return true;
	}
	else
	{
		return false;
	}
}
class MC {
private:
	int MissionaryNum;//传教士数量
	int CannibalsNum;//野人数量
	int BoatNum;//船只数量
	vector<bank>  BanksOpen;//存放open表
	vector<bank>  BanksClose;//close表
	bank beginPath;//开始的路径点
	bank succesPath;//最后的路径点
	int BoatMove[500][3];//操作集合:过河的传教士人数和野人人数,出发地:左岸为1,右岸为0;
	int BoatMoveSize;
public:
	MC(int m, int c, int b);
	~MC() {}
	//查找所有子节点
	void SearchSonPoint();
	//判断节点状态是否合法
	bool JudgePointState(bank thisBank);
	//判断节点是否已生成
	bool JudgePointCreated(bank thisBank,int& index,int& who);
	//比较该节点本父节点的代价和新父节点代价,本来小,返回 true,否则false
	bool JudgeCost(int index, int who, bank newFatherBank);
	//判断是否已完成任务
	bool JudgeAchievement(bank thisBank2);
	//改变所有该节点的子节点的值
	void ChangeSonPointCost(int index);
	//寻找该属性的索引值
	int FoundIndex(bank thisBank);
	//返回一个路径点集合
	vector<bank> ReturnResult();
	//打印列表
	void Output();
};
void MC::Output()
{
	vector<bank> result = ReturnResult();
	if (result.size() == 0)
	{
		cout << "无解" << endl;
	}
	else
	{
		for (int i = result.size() - 1; i > 0; i--)
		{
			cout << "左岸" << endl;
			cout << "修道士:" << result.at(i).MissionaryNum << "人      野人:" << result.at(i).CannibalsNum << "人" << endl;
			if (i != 0)
			{
				if (result.at(i).BoatInHere == 1)
				{
					cout << abs(result.at(i).CannibalsNum - result.at(i - 1).CannibalsNum) << "个野人从左岸移到右岸" << endl;
					cout << abs(result.at(i).MissionaryNum - result.at(i - 1).MissionaryNum) << "个传教士从左岸移到右岸" << endl;
				}
				else
				{
					cout << abs(result.at(i).CannibalsNum - result.at(i - 1).CannibalsNum) << "个野人从右岸移到左岸" << endl;
					cout << abs(result.at(i).MissionaryNum - result.at(i - 1).MissionaryNum) << "个传教士从右岸移到左岸" << endl;
				}
			}
			cout << "右岸" << endl;
			cout << "修道士:" << MissionaryNum - result.at(i).MissionaryNum << "人      野人:" << CannibalsNum - result.at(i).CannibalsNum << "人" << endl << endl;
		}
	}
	
}
vector<bank> MC::ReturnResult()
{
	vector<bank> result;
	if (succesPath == beginPath)
	{

	}
	else
	{
		result.push_back(succesPath);
		bank judge = succesPath;
		while (judge.FatherPoint != -1)
		{
			judge = BanksClose.at(judge.FatherPoint);
			result.push_back(judge);
		}
	}
	
	return result;
}

void MC::ChangeSonPointCost(int index)
{
	for (int i = 0; i < BanksOpen.size(); i++)
	{
		if (BanksOpen.at(i).FatherPoint == index)
		{
			BanksOpen.at(i).OrderNumber = BanksClose.at(index).OrderNumber + 1;
		}
	}
	for (int i = 0; i < BanksClose.size(); i++)
	{
		if (BanksClose.at(i).FatherPoint == index)
		{
			BanksClose.at(i).OrderNumber = BanksClose.at(index).OrderNumber + 1;
			int fatherPointIndex = FoundIndex(BanksClose.at(i));
			ChangeSonPointCost(fatherPointIndex);
		}
	}
}

int MC::FoundIndex(bank thisBank)
{
	vector<bank>::iterator it = find(BanksClose.begin(), BanksClose.end(), thisBank);
	int fatherPoint;
	if (it != BanksClose.end())
	{
		fatherPoint = distance(BanksClose.begin(), it);
	}
	return fatherPoint;
}
void MC::SearchSonPoint() {
	//只有当open表不为空时查找子节点
	bank thisBank;//存放当前节点
	bank sonBank;//存放生成的子节点
	while (BanksOpen.size() > 0)
	{
		thisBank = BanksOpen.at(0);
		if (JudgeAchievement(thisBank))
		{
			break;
		}
		BanksOpen.erase(begin(BanksOpen));
		BanksClose.push_back(thisBank);//将根节点转移到close表
		for (int i = 0; i < BoatMoveSize; i++)
		{
			//生成节点
			if (BoatMove[i][2] != thisBank.BoatInHere)
			{
				continue;
			}
			else
			{
				if (BoatMove[i][2]==1)
				{
					sonBank.BoatInHere = abs(thisBank.BoatInHere - 1);
					sonBank.MissionaryNum = thisBank.MissionaryNum - BoatMove[i][0];
					sonBank.CannibalsNum = thisBank.CannibalsNum - BoatMove[i][1];
					sonBank.FatherPoint = BanksClose.size() - 1;
					sonBank.OrderNumber = thisBank.OrderNumber + 1;
				}
				else
				{
					sonBank.BoatInHere = abs(thisBank.BoatInHere + 1);
					sonBank.MissionaryNum = thisBank.MissionaryNum + BoatMove[i][0];
					sonBank.CannibalsNum = thisBank.CannibalsNum + BoatMove[i][1];
					sonBank.FatherPoint = BanksClose.size() - 1;
					sonBank.OrderNumber = thisBank.OrderNumber + 1;
				}
				if (JudgePointState(sonBank))
				{
					continue;
				}
				
				int index, who;
				//如果创建了
				if (JudgePointCreated(sonBank,index,who))
				{
					if (JudgeCost(index,who, thisBank))
					{
						//原来的花费少,所以不用改变父指针
					}
					else
					{
						//改变
						//在open里
						if (who == 0)
						{
							BanksOpen[index].FatherPoint = BanksClose.size()-1;
							BanksOpen[index].OrderNumber = thisBank.OrderNumber + 1;

						}
						//在close里 
						else
						{
							BanksClose[index].FatherPoint = BanksClose.size() - 1;
							BanksClose[index].OrderNumber = thisBank.OrderNumber + 1;
							int fatherPoint = FoundIndex(sonBank);
							ChangeSonPointCost(fatherPoint);
						}
					}
				}
				//如果没创建,放在数组后面
				else {
					BanksOpen.insert(BanksOpen.begin(),sonBank);

					if (JudgeAchievement(sonBank))
					{

						succesPath = sonBank;
						goto h;
					}
				}
			}
		}
	}
	h:
	cout <<"完成查找"<< endl;
}
//判断是否违规
bool  MC::JudgePointState(bank thisBank)
{
	if (
		thisBank.CannibalsNum > thisBank.MissionaryNum && thisBank.MissionaryNum!=0 ||
		CannibalsNum- thisBank.CannibalsNum >MissionaryNum- thisBank.MissionaryNum && MissionaryNum - thisBank.MissionaryNum!=0||
		thisBank.CannibalsNum>CannibalsNum||
		thisBank.CannibalsNum<0||
		thisBank.MissionaryNum>MissionaryNum||
		thisBank.MissionaryNum<0
		)
	{
		//cout << "违规" << endl;
		return true;
	}
	else
	{
		//cout << "不违规" << endl;

		return false;
	}
}
//index是下标,who是那个表
bool MC::JudgePointCreated(bank thisBank, int& index, int& who)
{
	for (int i = 0; i < BanksOpen.size(); i++)
	{
		if (thisBank == BanksOpen.at(i))
		{
			index = i;
			who = 0;
			return true;
		}
	}
	for (int i = 0; i < BanksClose.size(); i++)
	{
		if (thisBank == BanksClose.at(i))
		{
			index = i;
			who = 1;
			return true;
		}
	}
	return false;
}
bool MC::JudgeCost(int index,int who, bank newFatherBank)
{
	if (who == 0)
	{
		if (BanksOpen.at(index).OrderNumber<newFatherBank.OrderNumber+1)
		{
			return true;
		}
		else
		{
			return false;
		}
	}
	else
	{
		if (BanksClose.at(index).OrderNumber < newFatherBank.OrderNumber + 1)
		{
			return true;
		}
		else
		{
			return false;
		}
	}
	

}

bool MC::JudgeAchievement(bank thisBank2)
{
	//当前的节点是否是最终的节点
	if (thisBank2.BoatInHere == 0 && thisBank2.MissionaryNum == 0 && thisBank2.CannibalsNum == 0) {
		
		return true;
	}
	else
	{
		return  false;
	}
	//cout << "判断最终节点完成" << endl;

}

MC::MC(int m,int c,int b){
	MissionaryNum = m;
	CannibalsNum = c;
	BoatNum = b;
	BoatMoveSize = 0;
	//初始化操作集合
	int k = 0;
	for (int i = 0; i <= b; i++)
	{
		for (int j = 0; j <= b-i; j++)
		{
			if (i + j <= b && i+j!=0)
			{
				BoatMove[k][0] = i;
				BoatMove[k][1] = j;
				BoatMove[k][2] = 0;
				//cout << BoatMove[k][0] <<","<< BoatMove[k][1] << "," << BoatMove[k][2] << endl;
				BoatMoveSize += 1;
				k++;
			}
		}
	}
	for (int i = 0; i <= b; i++)
	{
		for (int j = 0; j <= b - i; j++)
		{
			if (i + j <= b && i + j != 0)
			{
				BoatMove[k][0] = i;
				BoatMove[k][1] = j;
				BoatMove[k][2] = 1;
				//cout << BoatMove[k][0] << "," << BoatMove[k][1] << "," << BoatMove[k][2] << endl;
				BoatMoveSize += 1;
				k++;
			}
		}
	}
	//cout << BoatMoveSize << endl;
	//初始化open表,初始状态为n,n,1
	bank elem;
	elem.BoatInHere = 1;
	elem.FatherPoint = -1;
	elem.CannibalsNum = CannibalsNum;
	elem.MissionaryNum = MissionaryNum;
	elem.OrderNumber = 0;
	succesPath = elem;
	beginPath = elem;
	BanksOpen.push_back(elem);
	//初始化close表 ,初始为0
	//cout << "初始化完成" << endl;
}

int main() {
	int M, C, B;
	cin >> M;
	cin >> C;
	cin >> B;
	MC mcpro(M, C, B);
	mcpro.SearchSonPoint();
	mcpro.Output();

	return 0;
}

算法写的很垃圾,仅作记载用,有建议或者错误可以留言一起交流

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值