2021-03-12

实验任务二:隐藏式图的搜索问题 ——(代码实现)

//A*算法
#include <iostream>
using namespace std;


//输入203184765

struct ENode
{
	int status[9];
	int G;
	int H;
	int F;
	int Zero;
	int step;
	ENode* Parent;
};

//最终状态
int FinalStatus[9] = { 1, 2, 3, 8, 0, 4, 7, 6, 5 };

//定义OPEN表和CLOSE表,open和close是表中最后一个内容的下一位序号
ENode OPEN[MAXLISTSIZE];
ENode CLOSE[MAXLISTSIZE];
int open = 0;
int close = 0;

ENode* Node;

/*
计算不在位的将牌数H
返回 H
*/
int CountH(int* status)
{
	int H = 0;
	int i;
	for (i = 0; i <= 8; i++)
	{
		if (FinalStatus[i] != status[i])
		{
			H++;
		}
	}
	return H;
}

/*
判断新生成的节点是否已经存在于OPEN表或CLOSE表中
返回 表征是否存在于OPEN或CLOSE的值,值为0 均不在,值>0 只在OPEN表,值<0 只在CLOSE表,|值|-1表示所在列表中的位置
*/
int Exist(ENode* N)
{
	int i, j;
	int H = 0;                      //计算不在位的将牌数,如果为0,则证明给函数的节点在表中已存在
	int status[9];

	Node = new ENode;
	Node = N;

	for (i = 0; i <= 8; i++)
	{
		status[i] = Node->status[i];
	}

	for (i = 0; i <= open - 1; i++)     //判断是否在OPEN表
	{
		for (j = 0; j <= 8; j++)
		{
			if (status[j] != OPEN[i].status[j])
			{
				H++;
			}
		}

		if (H == 0)                 //H=0证明在表中找到该节点
		{
			return i + 1;           //如果在OPEN表中,返回i(节点在OPEN的位置)+ 1(在OPEN找到该节点)
		}
		H = 0;                      //扫描完一个节点后重置H
	}

	for (i = 0; i <= close - 1; i++)     //判断是否在CLOSE表
	{
		for (j = 0; j <= 8; j++)
		{
			if (status[j] != CLOSE[i].status[j])
			{
				H++;
			}
		}

		if (H == 0)                 //H=0证明在表中找到该节点
		{
			return (-i) - 1;        //如果在CLOSE表中,返回-i(i为节点在CLOSE的位置)- 1(在CLOSE找到该节点)
		}
		H = 0;                      //扫描完一个节点后重置H
	}

	return 0;
}

/*
初始化节点
返回 初始化后的节点Node
*/
ENode* ENodeInit(int* status, int zero, int g, ENode* parent, int step)
{
	int i;
	Node = new ENode;
	for (i = 0; i <= 8; i++)
	{
		Node->status[i] = status[i];
	}
	Node->Zero = zero;
	Node->G = g;
	Node->H = CountH(Node->status);
	Node->F = Node->G + Node->H;
	Node->Parent = parent;
	Node->step = step;
	return Node;
}

/*
左移后的变化
返回 左移后的状态
*/
int* Left(int* s, int z)
{
	int temp, i;
	static int status[9];
	for (i = 0; i <= 8; i++)
	{
		status[i] = s[i];
	}
	temp = status[z - 1];
	status[z - 1] = 0;
	status[z] = temp;
	return status;
}

/*
右移后的变化
返回 右移后的状态
*/
int* Right(int* s, int z)
{
	int temp, i;
	static int status[9];
	for (i = 0; i <= 8; i++)
	{
		status[i] = s[i];
	}
	temp = status[z + 1];
	status[z + 1] = 0;
	status[z] = temp;
	return status;
}

/*
上移后的变化
返回 上移后的状态
*/
int* Up(int* s, int z)
{
	int temp, i;
	static int status[9];
	for (i = 0; i <= 8; i++)
	{
		status[i] = s[i];
	}
	temp = status[z - 3];
	status[z - 3] = 0;
	status[z] = temp;
	return status;
}

/*
下移后的变化
返回 下移后的状态
*/
int* Down(int* s, int z)
{
	int temp, i;
	static int status[9];
	for (i = 0; i <= 8; i++)
	{
		status[i] = s[i];
	}
	temp = status[z + 3];
	status[z + 3] = 0;
	status[z] = temp;
	return status;
}

/*
判断子节点是否在OPEN或CLOSE中,并进行对应的操作
返回值 NULL
*/
void ExistAndOperate(ENode* N)
{
	int i;
	int inList;                 //定义表示新生成节点是否在OPEN表或CLOSE表中, 值为0 均不在,值>0 只在OPEN表,值<0 只在CLOSE表

	Node = new ENode;
	Node = N;

	if (Node->G == 1)           //如果是第一步的节点,直接加入OPEN中,返回
	{
		OPEN[open] = *Node;
		open++;
		return;
	}

	inList = Exist(Node);       //判断新节点是否在OPEN或CLOSE中

	if (inList == 0)            //如果均不在两个表中,将节点加入OPEN表中
	{
		OPEN[open] = *Node;      //将拓展出的新结点加入到OPEN表中
		open++;
	}

	else if (inList > 0)             //如果在OPEN中,说明从初始节点到该节点找到了两条路径,保留耗散值短的那条路径
	{
		if (OPEN[inList - 1].F > Node->F)    //如果表内节点F值大于新节点F值,用新节点代替表内节点
		{
			OPEN[inList - 1] = *Node;
		}
	}

	else if (inList < 0)             //如果在CLOSE中,说明初始节点到该节点有两条路径,如果新找到的路径耗散值大,什么都不做,如果较小,将其从CLOSE中取出放入OPEN中    
	{
		inList = -inList;
		if (CLOSE[inList - 1].F > Node->F)       //如果较小
		{
			OPEN[open] = *Node;       //将其取出放入OPEN
			open++;
		}
		for (i = inList - 1; i <= close - 1; i++)     //将其在CLOSE中释放
		{
			CLOSE[i] = CLOSE[i + 1];
		}
		close--;
	}
}

/*
寻找最佳路径函数
返回 最后的节点Node
*/
ENode* Search()
{
	int* status;
	int i, j;

	ENode* Temp;

	while (1)                   //一直循环知道找到解结束
	{
		Temp = new ENode;

		for (i = open - 1; i > 0; i--)    //用冒泡排序给OPEN表里面的节点按耗散值进行排序
		{
			for (j = 0; j < i; j++)
			{
				if (OPEN[j].F > OPEN[j + 1].F)
				{
					*Temp = OPEN[j + 1];
					OPEN[j + 1] = OPEN[j];
					OPEN[j] = *Temp;
				}
			}
		}

		Node = new ENode;
		*Node = OPEN[0];                 //从OPEN表中取出第一个元素(F值最小)进行扩展

		if (!CountH(Node->status))      //判断该节点是否是目标节点,若是,则不在位的将牌数为0,算法结束
		{
			break;
		}

		Temp = Node;
		CLOSE[close] = *Node;            //将扩展过的节点放入CLOSE    
		close++;
		for (i = 0; i <= open - 1; i++) //将扩展的节点从OPEN中释放
		{
			OPEN[i] = OPEN[i + 1];
		}
		open--;

		if ((Temp->Zero) % 3 >= 1)        //如果能左移,则进行左移创造新结点    
		{
			Node = new ENode;                                           //创造新结点
			status = Left(Temp->status, Temp->Zero);                   //得到新的状态
			Node = ENodeInit(status, Temp->Zero - 1, (Temp->G) + 1, Temp, 1);    //初始化新结点
			ExistAndOperate(Node);      //判断子节点是否在OPEN或CLOSE中,并进行对应的操作
		}

		if ((Temp->Zero) % 3 <= 1)        //如果能右移,则进行右移创造新结点    
		{
			Node = new ENode;                                           //创造新结点
			status = Right(Temp->status, Temp->Zero);                   //得到新的状态
			Node = ENodeInit(status, Temp->Zero + 1, (Temp->G) + 1, Temp, 2);    //初始化新结点
			ExistAndOperate(Node);      //判断子节点是否在OPEN或CLOSE中,并进行对应的操作
		}

		if (Temp->Zero >= 3)            //如果能上移,则进行上移创造新结点    
		{
			Node = new ENode;                                           //创造新结点
			status = Up(Temp->status, Temp->Zero);                   //得到新的状态
			Node = ENodeInit(status, Temp->Zero - 3, (Temp->G) + 1, Temp, 3);    //初始化新结点
			ExistAndOperate(Node);      //判断子节点是否在OPEN或CLOSE中,并进行对应的操作
		}

		if (Temp->Zero <= 5)            //如果能下移,则进行下移创造新结点    
		{
			Node = new ENode;                                           //创造新结点
			status = Down(Temp->status, Temp->Zero);                   //得到新的状态
			Node = ENodeInit(status, Temp->Zero + 3, (Temp->G) + 1, Temp, 4);    //初始化新结点
			ExistAndOperate(Node);      //判断子节点是否在OPEN或CLOSE中,并进行对应的操作
		}

		if (open == 0)                  //如果open=0, 证明算法失败, 没有解
			return NULL;
	}
	return Node;
}

/*
展示具体步骤
返回 NULL
*/
void ShowStep(ENode* Node)
{
	int STEP[MAXSTEPSIZE];
	int STATUS[MAXSTEPSIZE][9];
	int step = 0;
	int i, j;
	int totalStep = Node->G;
	while (Node)
	{
		STEP[step] = Node->step;
		for (i = 0; i <= 8; i++)
		{
			STATUS[step][i] = Node->status[i];
		}
		step++;
		Node = Node->Parent;
	}
	cout << "----------------------" << endl;
	cout << totalStep << endl;
	cout << "----------------------" << endl;
	for (i = step - 1; i >= 0; i--)
	{
		if (STEP[i] == 1)
			cout << "left";
		else if (STEP[i] == 2)
			cout << "right";
		else if (STEP[i] == 3)
			cout << "up";
		else if (STEP[i] == 4)
			cout << "down";
		else if (STEP[i] == 0)
			cout << "START";
		cout << " ";
	}
	cout << endl << "----------------------" << endl;
	for (i = step - 1; i >= 0; i--)
	{
		for (j = 0; j <= 8; j++)
		{
			cout << STATUS[i][j];
			if (j == 2 || j == 5 || j == 8)
				cout << endl;
			else
				cout << " ";
		}
		cout << "----------------------" << endl;
	}
}

/*
主函数
返回 0
*/
int main()
{
	int fstatus[9];
	int i;
	ENode* FNode;
	ENode* EndNode;

	for (i = 0; i <= 8; i++)                    //输入初始状态
	{
		cin >> fstatus[i];
	}

	for (i = 0; i <= 8; i++)                    //判断0节点位置
	{
		if (fstatus[i] == 0)
			break;
	}

	FNode = ENodeInit(fstatus, i, 0, NULL, 0);  //获得初始节点

	OPEN[open] = *FNode;                         //将初始节点放入OPEN中
	open++;
	EndNode = Search();                         //寻找最佳路径

	if (!EndNode)
		cout << "无解" << endl;
	else
		ShowStep(EndNode);                      //展示步骤

	return 0;
}

运行结果
在这里插入图片描述

embedcpp-2021-03是一个有关嵌入式C++编程的课程,于2021年3月举办。嵌入式C++编程是指在嵌入式系统中使用C++编程语言进行开发的一种方法。 在嵌入式系统中,资源通常是有限的,例如处理器速度、内存容量和存储空间等。因此,使用C++编程语言可以提供更高的灵活性和效率,帮助开发人员充分利用有限的资源。C++在嵌入式系统中的应用范围广泛,例如物联网设备、汽车电子和工业自动化等领域。 embedcpp-2021-03课程旨在向学员介绍嵌入式C++编程的基础知识和技巧。课程内容通常包括以下方面: 1. C++语法和特性:介绍C++的基本语法、面向对象编程和泛型编程等概念,以及C++11、C++14和C++17的一些新特性。 2. 嵌入式系统概述:了解嵌入式系统的基本特点、硬件和软件组成,以及与传统桌面开发的区别。 3. 低级编程:学习如何与硬件交互,包括使用寄存器、配置外设和处理中断等。还可以介绍使用汇编语言优化性能的技巧。 4. 内存管理:探讨嵌入式系统中的内存管理技术,包括堆栈和堆的使用、动态内存分配和对象生命周期管理等。 5. 实时操作系统(RTOS):介绍嵌入式系统中常用的实时操作系统,如FreeRTOS和µC/OS等,学习如何使用RTOS进行任务调度和资源管理。 除了理论知识,embedcpp-2021-03课程通常还包括实际的项目练习,以帮助学员将所学知识应用于实际场景。通过该课程,学员可以了解嵌入式C++编程的基础概念和实践技巧,为嵌入式系统开发提供了一定的基础。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值