实验要求
用A*算法来解决八数码问题。
代码实现
#include<iostream>
#include<stdio.h>
#include<cmath>
using namespace std;
int open_cnt=0;
int open_node_cnt;//open表节点个数
int close_cnt=0;
int noresoult=0;
struct Node{
int a[3][3];
int x,y;
int f,g,h;
int flag; //上一次移动方向
Node *father;
}start,end;
struct Open_Close{
int f;
Node *np;
}open[10000],close[10000];
bool isable(){//判断是否有解,逆序数之和奇偶性相同,有解
int s[9],e[9];
int tf=0,ef=0;
int k=0;
for(int i=0;i<3;i++){
for(int j=0;j<3;j++){
s[k]=start.a[i][j];
e[k]=end.a[i][j];
k++;
}
}
for(int i=0;i<9;i++){
for(int j=0;j<i;j++){
if(s[i]>s[j]&&s[j]!=0) tf+=1;
if(e[i]>e[j]&&e[j]!=0) ef+=1;
}
}
if((tf%2==1&&ef%2==1)||(tf%2==0&&ef%2==0)) return true;
else return false;
}
int a_start_h(Node *node){ //求 h()
int old_x,old_y,end_x,end_y;
int h=0;
for(int k=1;k<9;k++){
for(int i=0;i<3;i++){
for(int j=0;j<3;j++){
if(node->a[i][j]==k){
old_x=i;
old_y=j;
}
if(end.a[i][j]==k){
end_x=i;
end_y=j;
}
}
}
h+=abs(old_x-end_x)+abs(old_y-end_y);
}
return h;
}
void input(){ //输入
for(int i=0;i<3;i++){
for(int j=0;j<3;j++){
cin>>start.a[i][j];
if(start.a[i][j]==0){
start.x=i;
start.y=j;
}
}
}
for(int i=0;i<3;i++){
for(int j=0;j<3;j++){
cin>>end.a[i][j];
if(end.a[i][j]==0){
end.x=i;
end.y=j;
}
}
}
start.g=0;
start.h=a_start_h(&start);
start.f=start.g+start.h;
}
int show(Node *node){ //显示
Node *p=node;
if(p==&start) return 1;
else show(p->father);
cout<<"==============\n";
for(int i=0;i<3;i++){
for(int j=0;j<3;j++){
cout<<p->a[i][j]<<" ";
}
printf("\n");
}
cout<<"==============\n\n";
}
bool isend(Node *node){ //判断是否为目标节点
for(int i=0;i<3;i++){
for(int j=0;j<3;j++){
if(node->a[i][j]!=end.a[i][j])
return false;
}
}
return true;
}
void sort(Open_Close *open){ //open表排序
int min=99999,min_flag=0;
Open_Close temp;
for(int i=0;i<=open_cnt;i++){
if(min>open[i].f&&open[i].f>0){
min=open[i].f;
min_flag=i;
}
}
temp=open[min_flag];
open[min_flag]=open[0];
open[0]=temp;
}
void move(int flag,Node *node){ //向四个方向扩展
int temp;
if(flag==1&&node->x>0){
Node *n = new Node();
for(int i=0;i<3;i++){
for(int j=0;j<3;j++){
n->a[i][j]=node->a[i][j];
}
}
n->a[node->x][node->y]=node->a[node->x-1][node->y];
n->a[node->x-1][node->y]=0;
n->x=node->x-1;
n->y=node->y;
n->flag=3;
n->father=node;
n->g=node->g+1; // 求 g()
n->h=a_start_h(n);
n->f=n->g+n->h;
open_cnt++;
open_node_cnt++;
open[open_cnt].np=n; //添加到open表
open[open_cnt].f=n->f; // 求 f()
}
else if(flag==2&&node->y<2){
Node *n = new Node();
for(int i=0;i<3;i++){
for(int j=0;j<3;j++){
n->a[i][j]=node->a[i][j];
}
}
n->a[node->x][node->y]=node->a[node->x][node->y+1];
n->a[node->x][node->y+1]=0;
n->x=node->x;
n->y=node->y+1;
n->flag=4;
n->father=node;
n->g=node->g+1; // 求 g()
n->h=a_start_h(n);
n->f=n->g+n->h;
open_cnt++;
open_node_cnt++;
open[open_cnt].np=n; //添加到open表
open[open_cnt].f=n->f; // 求 f()
}
else if(flag==3&&node->x<2){
Node *n = new Node();
for(int i=0;i<3;i++){
for(int j=0;j<3;j++){
n->a[i][j]=node->a[i][j];
}
}
n->a[node->x][node->y]=node->a[node->x+1][node->y];
n->a[node->x+1][node->y]=0;
n->x=node->x+1;
n->y=node->y;
n->flag=1;
n->father=node;
n->g=node->g+1; // 求 g()
n->h=a_start_h(n);
n->f=n->g+n->h;
open_cnt++;
open_node_cnt++;
open[open_cnt].np=n; //添加到open表
open[open_cnt].f=n->f; // 求 f()
}
else if(flag==4&&node->y>0){
Node *n = new Node();
for(int i=0;i<3;i++){
for(int j=0;j<3;j++){
n->a[i][j]=node->a[i][j];
}
}
n->a[node->x][node->y]=node->a[node->x][node->y-1];
n->a[node->x][node->y-1]=0;
n->x=node->x;
n->y=node->y-1;
n->flag=2;
n->father=node;
n->g=node->g+1; // 求 g()
n->h=a_start_h(n);
n->f=n->g+n->h;
open_cnt++;
open_node_cnt++;
open[open_cnt].np=n; //添加到open表
open[open_cnt].f=n->f; // 求 f()
}
}
void expand(Node *node){ //节点扩展
for(int i=1;i<5;i++){
if(i!=node->flag) move(i,node);
}
}
int main(){
input();
open[0].np=&start;//start放入open表
open_node_cnt=1;
if(isable()){
while(true){//open表不为空
if(isend(open[0].np)){
cout<<"\n路径:\n";
show(open[0].np);
break;
}
expand(open[0].np);//扩展最优节点的子节点
open[0].np=NULL;
open[0].f=-1;
open_node_cnt--;
sort(open); //open表排序
}
}
else cout<<"无解";
}
/*
有解
1 0 3
7 2 4
6 8 5
1 2 3
8 0 4
7 6 5
无解
1 2 3
4 0 7
6 5 8
3 2 1
6 5 0
4 7 8
*/