八数码全局择优搜索

全局择优搜索求解八数码问题

Step 1:
初始化初始节点信息和目的节点信息
void chushihua(Node& S,Node& G)
Step 2:
计算初始节点与目标节点的逆序数,判断初始节点与目的节点是否可达,若不可达,则输出“无解”,若可达,则转至Step 3
void nixushu(Node &S,Node &G)
Step 3:
对于全局择优搜索
void opencloseoperator(Node S0,Node Sg)
Step 3.1
将初始节点放入open表中
Step 3.2
从open表中取出一个节点node,并将node存入close表中
Step 3.3
判断node是否为目标节点。
bool judge(Node S, Node G)
若是,则将路径信息输出,并输出最小移动步数,求解结束,
否则,移动node节点中的空格,查找符合移动方向且可到达的后继节点,并求出后继节点的估计值,将后继节点加入到open表中。
void move(Node& S, Node G)

#include<queue>
#include<iostream>
#include "stdlib.h" 
#include<stack>
using namespace std;
#define num 9
struct Node{
	int bashumaarr[9];            //八数码设置
	struct Node* parent;     //设置父节点
	int h;                   //设置估计函数值
	friend bool operator < (Node A, Node B) //按照value值小的方案构造优先级队列
	{
		return A.h > B.h;
	}
};

priority_queue<Node> open;     //open表
queue<Node> close;     //close表
int count1=0,count2=0;         //用于逆序数判断
/*初始化初始棋局与目标棋局*/
void chushihua(Node& S,Node& G){
	int i;
	S.parent=NULL;	
	S.h=0;
	G.parent=NULL;		
	G.h=0;
	 cout<<"请输入初始状态:\n";
	 for( i=0;i<num;i++)
		 cin>>S.bashumaarr[i];
	 cout<<"请输入目标状态:\n";
	  for( i=0;i<num;i++)
		  cin>>G.bashumaarr[i];
	  cout<<"初始状态:"<<endl;
      for(i=0;i<9;i++)
	  {
		  cout<<S.bashumaarr[i]<<" ";
		  if((i+1)%3==0)
			  cout<<endl;
	  }
	  cout<<"目标状态:"<<endl;
      for(i=0;i<9;i++)
	  {
		  cout<<G.bashumaarr[i]<<" ";
		  if((i+1)%3==0)
			  cout<<endl;
	  }
	  cout<<"============"<<endl;
}
/*判断逆序数奇偶性*/
void nixushu(Node &S,Node &G)
{
	int i,j;
	for( i=0;i<=num-2;i++)  //初始棋局逆序数对
		  for( j=i+1;j<num;j++)
			if(S.bashumaarr[i]>S.bashumaarr[j]&&S.bashumaarr[i]!=0&&S.bashumaarr[j]!=0)
				count1++;

	   for( i=0;i<=num-2;i++)//目标棋局逆序数对
		  for( j=i+1;j<num;j++)
			if(G.bashumaarr[i]>G.bashumaarr[j]&&G.bashumaarr[i]!=0&&G.bashumaarr[j]!=0)
				count2++;


	   if(count1%2!=count2%2)//初始棋局与目标棋局奇偶性不同,则无解
	   {
		   cout<<"无解!"<<endl;
	   }
}
/*获取当前节点与目标节点位置不同的个数*/
int gujihanshu(Node A,Node G){
	int count=0;
	
	for(int i=0;i<num;i++)
		if(A.bashumaarr[i]!=G.bashumaarr[i])//&&G.state[i]!=0)
			count++;

	return count; //+A.depth;

}
/*判断node是否为目标节点*/
bool judge(Node S, Node G)
{
	for (int i = 0; i <= 8; i++)
	{
		if (S.bashumaarr[i] != G.bashumaarr[i])
		{
			return false;
		}
	}
	return true;
}
/*空格移动*/
void move(Node& S, Node G)
{
	/* 计算原状态下,空格所在的行列数,从而判断空格可以往哪个方向移动 */
	int locate0; //定义空格下标
	for(locate0=0;locate0<9&&S.bashumaarr[locate0]!=0;locate0++) ;//找到空白格

	int x =locate0 / 3, y = locate0 % 3; //获取空格所在行列编号

	for (int d = 0; d < 4; d++)   //向外扩展移动
	{   
		int newX=x,newY=y;//新空白格坐标
		Node tempNode;

		/*移动空白格*/
		if(d==0)  newX = x -1;
	    if(d==1)	 newY = y -1;
	    if(d==2)  newX = x +1;
	    if(d==3)	 newY = y +1;

		int newlocate0 = newX * 3 + newY; //空格新的位置

		if (newX >= 0 && newX < 3 && newY >= 0 && newY < 3) //判断是否可以移动
		{
			/* 产生移动后的八数码节点*/
			tempNode = S;
			tempNode.bashumaarr[locate0] = S.bashumaarr[newlocate0];
			tempNode.bashumaarr[newlocate0] =0;
/*如果新节点的0的位置和爷爷节点的0的位置一样,说明新节点是爷爷节点产生的父节点回退得到的,则舍弃该节点*/
			if ( S.parent!=NULL&&(*S.parent).bashumaarr[newlocate0] == 0) 
			{
				continue;
			}

			/* 获取估计值,把子节点加入open表中 */
			tempNode.parent = &S;
			tempNode.h = gujihanshu(tempNode, G);
			open.push(tempNode);
		}
	}
}
/*全局择优搜索,对open表和close表操作*/
void opencloseoperator(Node S0,Node Sg)
{
	open.push(S0);    //将初始节点放入open表中
		while (true)
		{
			close.push(open.top()); //从open表中取出一个节点node,并将node存入close表中
			open.pop(); //删除open表中优先级最高的元素
			if (!judge(close.back(), Sg)) //判断node是否为目标节点
			{
			move(close.back(), Sg);//node不是目标节点,移动node节点中的空格,查找符合移动方向且可达的后继节点
			}
			else
			{
				break;
			}
		}
		cout << "至少要移动" << close.size() - 1 << "步" << endl;
		while (close.size() != 0)
		{
			for (int i = 0; i <= 8; i++)
			{
				cout << close.front().bashumaarr[i]<<" ";
				if((i+1)%3==0)
					cout <<endl;
			}
			close.pop();
			cout<<"=====";
			cout << "\n";
		}
}
int main()
{
	Node S0,Sg;
	chushihua(S0,Sg);
	nixushu(S0,Sg);
	opencloseoperator(S0,Sg);
	return 0;
}

有解的输出结果
无解的运行结果

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值