全局择优搜索求解八数码问题
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;
}