A*算法求解八数码难题

初始状态:

2 3 8

1 6 4

7 0 5

目标状态:

1 2 3

8 0 4

7 6 5

提问:如何使用A*算法得到从初始状态到目标状态的搜索过程。

代码如下:

#include “pch.h”
#include
#include <stdlib.h>
#include <conio.h>
#include <math.h>
void Copy_node(struct node *p1, struct node *p2);//将p1指向的节点拷贝给p2
void Calculate_f(int deepth, struct node *p);//计算p节点的带价值
void Add_to_open(struct node *p);//将p加入open表中
void Add_to_closed(struct node *p);//将怕加入closed表中
void Remove_p(struct node *name, struct node *p);//从name中删除特定节点p
int Test_A_B(struct node *p1, struct node *p2);//判断两个节点状态是否相同
struct node * Search_A(struct node *name, struct node *temp);//在open或closed中搜索temp指向的节点相同的节点
void Print_result(struct node *p);//输出结果

struct node
{
int ss[3][3];//当前状态
int i_0;
int j_0;
int f;
int d;
int h;
struct node *father;//父节点
struct node *son;//子节点
};
struct node s_s = { {2,8,3,1,6,4,7,0,5},2,1,0,0,0,NULL,NULL };//初始节点,可根据具体需要变化
struct node s_e = { {1,2,3,8,0,4,7,6,5},1,1,0,0,0,NULL,NULL };//目标节点,可根据具体需要变化
struct node *open = NULL;
struct node *closed = NULL;
int sum_node = 0;

int main()
{
int bingo = 0;//成功的标志,成功bingo为1
struct node s;//头结点指针
struct node *n = NULL, *ls, *temp, *same;
Copy_node(&s_s, &s);//复制初始状态指针给头结点
Calculate_f(0, &s);
Add_to_open(&s);
while (open != NULL)
{
n = open;//n指向open表中当前扩展元素
ls = open->son;
Add_to_closed(n);
open = ls;//n指向的节点放进close表中
if (Test_A_B(n, &s_e))//当前节点与目标节点相同时,结束循环,否则继续
{
bingo = 1;
break;
}
else
if (n->j_0 >= 1)//空格列号不小于1,可左移
{
temp = n->father;
if (temp != NULL && temp->i_0 == n->i_0&&temp->j_0 - 1 == n->j_0)//新节点与父节点相同
;
else
{
temp = (struct node *)malloc(sizeof(struct node));//给新结点分配空间
Copy_node(n, temp);//拷贝n指向的节点状态
temp->ss[temp->i_0][temp->j_0] = temp->ss[temp->i_0][temp->j_0 - 1];//空格左移
temp->ss[temp->i_0][temp->j_0 - 1] = 0;
temp->j_0–;
temp->d++;
Calculate_f(temp->d, temp);//计算新节点带价值
temp->father = n;
if (same = Search_A(closed, temp))//close表中找到与新节点状态相同的节点
{
if (temp->f < same->f)
{
Remove_p(closed, same);
Add_to_open(temp);
sum_node++;
}
else;
}
else if (same = Search_A(open, temp))
{
if (temp->f < same->f)
{
Remove_p(open, same);
Add_to_open(temp);
sum_node++;
}
else;
}
else //新节点为完全不同状态的新节点,加入open
{
Add_to_open(temp);
sum_node++;
}
}
}//结束左移
if (n->j_0 <= 1)//空格列号不大于一,可以右移
{
temp = n->father;
if (temp != NULL && temp->i_0 == n->i_0&&temp->j_0 + 1 == n->j_0)
;
else //新节点与祖父节点不同,或其父节点为起始节点
{
temp = (struct node *)malloc(sizeof(struct node));
Copy_node(n, temp);
temp->ss[temp->i_0][temp->j_0] = temp->ss[temp->i_0][temp->j_0 + 1];
temp->ss[temp->i_0][temp->j_0 + 1] = 0;
temp->j_0++;
temp->d++;
Calculate_f(temp->d, temp);
temp->father = n;
if (same = Search_A(closed, temp))
{
if (temp->f < same->f)
{
Remove_p(closed, same);//从closed表中删除与remp指向状态相同的节点
Add_to_open(temp);
sum_node++;
}
else;
}
else if (same = Search_A(open, temp))
{
if (temp->f < same->f)
{
Remove_p(open, same);
Add_to_open(temp);
sum_node++;
}
else;
}
else
{
Add_to_open(temp);
sum_node++;
}
}
}//结束右移
if (n->i_0 >= 1)//空格所在列号不小于1,上移
{
temp = n->father;
if (temp != NULL && temp->i_0 == n->i_0 - 1 && temp->j_0 == n->j_0)
;
else
{
temp = (struct node *)malloc(sizeof(struct node));
Copy_node(n, temp);
temp->ss[temp->i_0][temp->j_0] = temp->ss[temp->i_0 - 1][temp->j_0];
temp->ss[temp->i_0 - 1][temp->j_0] = 0;
temp->i_0–;
temp->d++;
Calculate_f(temp->d, temp);
temp->father = n;
if (same = Search_A(closed, temp))
{
if (temp->f < same->f)
{
Remove_p(closed, same);
Add_to_open(temp);
sum_node++;
}
else;
}
else if (same = Search_A(open, temp))
{
if (temp->f < same->f)
{
Remove_p(open, same);
Add_to_open(temp);
sum_node++;
}
else;
}
else
{
Add_to_open(temp);
sum_node++;
}
}
}//结束上移
if (n->i_0 <= 1)//空格列号不大于一,下移
{
temp = n->father;
if (temp != NULL && temp->i_0 == n->i_0 + 1 && temp->j_0 == n->j_0)
;
else
{
temp = (struct node *)malloc(sizeof(struct node));
Copy_node(n, temp);
temp->ss[temp->i_0][temp->j_0] = temp->ss[temp->i_0 + 1][temp->j_0];
temp->ss[temp->i_0 + 1][temp->j_0] = 0;
temp->i_0++;
temp->d++;
Calculate_f(temp->d, temp);
temp->father = n;
if (same = Search_A(closed, temp))
{
if (temp->f < same->f)
{
Remove_p(closed, same);
Add_to_open(temp);
sum_node++;
}
else;
}
else if (same = Search_A(open, temp))
{
if (temp->f < same->f)
{
Remove_p(open, same);
Add_to_open(temp);
sum_node++;
}
else;
}
else
{
Add_to_open(temp);
sum_node++;
}
}
}//结束下移
}
if (bingo = 1)
{
if (n != NULL)
{
Print_result(n);
}
}
else
{
printf(“问题求解失败!”);
}
}
void Calculate_f(int deepth, struct node *p)
{
int i, j, temp;
temp = 0;
for (i = 0; i <= 2; i++) //计算所有“不在位”数码距离和
{
for (j = 0; j <= 2; j++)
{
if ((p->ss[i][j]) != (s_e.ss[i][j]))
temp++;
}
}
p->h = temp;
p->f = deepth + p->h;
}

void Add_to_open(struct node *p)//将p加入open表中
{
struct node *p1, *p2;
p1 = open;
p2 = NULL;
if (open == NULL)
{
p->son = NULL;
open = p;
}
else
{
while (p1 != NULL && p->f > p1->f)
{
p2 = p1;
p1 = p1->son;
}
if (p2 == NULL)
{
p->son = open;
open = p;
}
else if (p1 == NULL)
{
p->son = NULL;
p2->son = p;
}
else
{
p2->son = p;
p->son = p1;
}
}
}

void Add_to_closed(struct node *p)//将怕加入closed表中
{
if (closed == NULL)
{
p->son = NULL;
closed = p;
}
else
{
p->son = closed;
closed = p;
}
}

struct node * Search_A(struct node *name, struct node *temp)//在open或closed中搜索temp指向的节点相同的节点
{
struct node *p1;
p1 = name;
while (p1 != NULL)
{
if (Test_A_B(p1, temp))
return p1;
else
p1 = p1->son;
}
return NULL;
}

int Test_A_B(struct node *p1, struct node *p2)//判断两个节点状态是否相同
{
int i, j, flag;
flag = 1;
for (i = 0; i <= 2; i++)
for (j = 0; j <= 2; j++)
{
if ((p2->ss[i][j]) != (p1->ss[i][j])) { flag = 0; return flag; }
else;
}
return flag;
}

void Remove_p(struct node *name, struct node *p)//从name中删除特定节点p
{
struct node *p1, *p2;
p1 = NULL;
p2 = NULL;
if (name == NULL)
return;
else if (Test_A_B(name, p) && name->f == p->f)
{
open = name->son;
name->son = NULL;
return;
}
else
{
p2 = name;
p1 = p2->son;
while (p1)
{
if (Test_A_B(p1, p) && p1->f == p->f)
{
p2->son = p1->son;
return;
}
else
{
p2 = p1;
p1 = p1->son;
}
}
return;
}
}

void Copy_node(struct node *p1, struct node *p2)//将p1指向的节点拷贝给p2
{

int i, j;
for (i = 0; i <= 2; i++)
{
	for (j = 0; j <= 2; j++)
	{
		p2->ss[i][j] = p1->ss[i][j];
	}
}
p2->i_0 = p1->i_0;
p2->j_0 = p1->j_0;
p2->f = p1->f;
p2->d = p1->d;
p2->h = p1->h;
p2->son = p1->son;
p2->father = p1->father;

}

void Print_result(struct node *p)//输出结果
{
struct node *path[100];
struct node *temp, *temp_father;
int i, j, k;
for (i = 0; i <= 99; i++)
path[i] = 0;
temp = p;
printf(“总共扩展 %d 个节点\n”, sum_node);
printf(“总共扩展 %d 层\n”, temp->d);
printf(“解路径如下: \n”);
for (i = p->d; i >= 0; i–)
{
path[i] = temp;
temp = temp->father;
}
for (k = 0; k <= p->d; k++)
{
temp = path[k];
printf(“第%d步 “, temp->d);
if (k - 1 >= 0)
{
temp_father = path[k - 1];
if (temp->i_0 < temp_father->i_0)printf(”->上移\n”);
if (temp->i_0 > temp_father->i_0)printf("->下移\n");
if (temp->j_0 < temp_father->j_0)printf("->左移\n");
if (temp->j_0 > temp_father->j_0)printf("->右移\n");
}
else
printf("\n");
printf(“当前节点状态为: \n”);
for (i = 0; i <= 2; i++)
{
for (j = 0; j <= 2; j++)
{
printf("%d “, temp->ss[i][j]);
}
printf(”\n");
}
printf("\n");
}
}
本程序使用C++进行编写,可以在环境中直接运行,也可以根据个人需要修改初始、目标节点以及其他相关数据。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值