八数码宽度优先算法

相关代码要感谢网上的一些大神给予的分享

程序思路

结构体map

用来作为一个结点的数据结构。

struct Map
{
    int cell[N][N];//数码数组
    Direction BelockDirec;//操作符方向
    struct Map * Parent;//父节点
};

PrintMap

用来打印一个结点

void PrintMap(struct Map *map)
{
    cout<<"*************************************************"<<endl;
    for(int i=0;i<N;i++)
    {
        for(int j=0;j<N;j++)
        {
cout<<map->cell[i][j]<<"   ";
        }
cout<<endl;
    }
 cout<<"*************************************************"<<endl;
}

MoveMap

函数用来扩展一个结点的后继结点(上、下、左、右)

struct Map * MoveMap(struct Map * map,Direction Direct,bool CreateNewMap)
{
    struct Map * NewMap;


    //获取空闲格位置i,j
    int i,j;
    for(i = 0; i < N; i++)
    {
        bool HasGetBlankCell = false;
        for(j = 0; j < N; j++)
        {
            if(map->cell[i][j] == 0)
            {
                HasGetBlankCell = true;
                break;
            }
        }
        if(HasGetBlankCell)
            break;
    }
    //移动数字,t_i,t_j为移动后0的坐标
    int t_i = i,t_j = j;
    bool AbleMove = true;
    switch(Direct)
    {
    case Down:
        t_i++;
        if(t_i >= N)
            AbleMove=false;
        break;
    case Up:
        t_i--;
        if(t_i < 0)
            AbleMove=false;
        break;
    case Left:
        t_j--;
        if(t_j < 0)
            AbleMove=false;
        break;
    case Right:
        t_j++;
        if(t_j >= N)
            AbleMove=false;
        break;
    };

    if(!AbleMove)//不可以移动则返回原节点
    {
        return map;
    }

    if(CreateNewMap)
    {
        NewMap = new Map();
        for(int x = 0; x < N; x++)
            for(int y = 0; y < N; y++)
                NewMap->cell[x][y] = map->cell[x][y];
    }
    else
        NewMap = map;
/*移动即交换0与相应数字的位置*/
    NewMap->cell[i][j] = NewMap->cell[t_i][t_j];
    NewMap->cell[t_i][t_j] = 0;


    return NewMap;
}

RandomMap

函数用来随机产生beginMap

struct Map * RandomMap() //随机产生八数码数组
{
int a[9];
struct Map * NewMap;
    NewMap = new Map();
srand((unsigned)time(0));
for(int k = 0; k < 9; k++)
    {  
bool Isre = false;
a[k] = rand()%9;
for (int l = 0; l < k; l++)
{
if (a[k] == a[l])

Isre = true;
break;
}
}
if(Isre)
{
k = k - 1;
continue;
}
}
    for(int i = 0; i < N; i++)
    {    
for (int j = 0; j < N; j++)

NewMap->cell[i][j] = a[i*3+j];
}
    }
NewMap->Parent = NULL;
NewMap->BelockDirec = None;
return NewMap;
}

IsSuccess

函数用来判断某节点是否为目标结点

 bool IsSuccess(struct Map * map,struct Map * Target)
{
bool IsSuc = true;
    for(int i = 0; i < N; i++)
    {
        for(int j = 0; j < N; j++)
        {
            if(map->cell[i][j] != Target->cell[i][j])
{
IsSuc = false;
break;
}
        }
if(!IsSuc)
break;
    }
    return IsSuc;
}

BNF_Search

struct Map * BNF_Search(struct Map * begin,struct Map * Target)

用来进行宽度搜索(按照以下的流程)

因为CLOSED表是只进不出的,所以这里省略了CLOSED表,用P1保存CLOSED表中的最新结点。而OPEN表是一个队列,先进先出。程序是以链表作为数据结构的,而不是数组。所以可以通过指针回溯

//把begin结点放入OPEN表中

struct Map * p1, *p2, *p=NULL;//p1为要进入closed表中的结点,p2为p1扩展的结点,p为等于结果的结点
bool IsSucc = false;
queue<struct Map *> Queue;
if(IsSuccess(begin,Target))
return begin;
Queue.push(begin);


//begin是否为目标结点    

 if(IsSuccess(begin,Target))
return begin;

 

//OPEN表是否为空表,或是否已经找到结果              

  while(!Queue.empty() || p == NULL);

                     

//把第一个结点从OPEN表中移出,放入CLOSED表中(即p1中)

 p1 = Queue.front(); //返回queue中的第一个元素
Queue.pop();

 

//扩展当前结点

for (int i = 1; i <= 4; i++)
{
Direction Direct=(Direction)i;
            if(Direct == p1->BelockDirec)//跳过屏蔽方向,因为里面保存了之前前进的方向,防止回退
                continue;
p2 = MoveMap(p1,Direct,true);//p2为扩展的的结点

 

//如果可以扩展成功(即可以移动)则设置方向和父节点指针

 if(p2 != p1)//数码是否可以移动


p2->Parent = p1;
switch(Direct)//设置屏蔽方向,防止往回推
{
case Up:
p2->BelockDirec = Down;
break;
case Down:
p2->BelockDirec = Up;
break;
case Left:
p2->BelockDirec = Right;
break;
case Right:
p2->BelockDirec = Left;
break;
}
                      

//判断后继结点是否为目标结点,如果不是则将后继结点放入OPEN表中并循环从OPEN表中pop,如果是则返回当前结点

if (IsSuccess(p2,Target))
{
p = p2;
return p;
}
Queue.push(p2);
n++;

HasResult

函数返回一个结点逆序数的奇偶性用来判断八数码是否可以后的结果

如果奇偶相同说明有解,否则无解

int HasResult(struct Map *map) //返回逆序数的奇偶用来判断是否有解
{
int a=0;
char b[9];
//把map二维表变为数组
for(int i=0;i<N;i++)
{
for(int j=0;j<N;j++)
b[i*3+j]=map->cell[i][j];
}
for(i=0;i<9;i++)
{
for(int j=0;j<i;j++)
{
if((b[j]<b[i])&&b[j]!=0)
a++;
}
}
return a%2;
}

Main函数

随机生成begin结点,并定义target结点

定义a1,a2用来记录begin和target逆序数的奇偶性用以判断是否有解

int a1,a2;
Map Target;
Map *begin,*T;
begin=new Map;
    //设定目标图 [1 2 3],[8 0 4],[7 6 5]
Target.cell[0][0] = 1;
Target.cell[0][1] = 2;
Target.cell[0][2] = 3;
Target.cell[1][0] = 8;
Target.cell[1][1] = 0;
Target.cell[1][2] = 4;
Target.cell[2][0] = 7;
Target.cell[2][1] = 6;
Target.cell[2][2] = 5;
begin = RandomMap();
cout<<"目标图:"<<endl;
PrintMap(&Target);
cout<<"起始图:"<<endl;
    PrintMap(begin);
a1=HasResult(&Target);
a2=HasResult(begin);
if(a1!=a2)
cout<<"无解"<<endl;

 

如果有解则进行BNF搜索并打印结果:

else
{
double start=clock();
cout<<"有解"<<endl;

//图搜索
T=BNF_Search(begin,&Target);
//打印
if(T != NULL)
{
//把路径倒序
Map *p=T;
stack<Map *> result_Stack1;  //栈,先进后出
while(p->Parent != NULL)
{
result_Stack1.push(p);
p = p->Parent;
}
cout<<"搜索结果:"<<endl;
while(!result_Stack1.empty())
{
PrintMap(result_Stack1.top());
c++;
result_Stack1.pop();//删除
}
cout<<"\n完成!"<<endl;
cout<<"路径长度为:"<<c<<endl;
double end=clock();
cout<<"程序运行的时间为:"<<end-start<<endl;
}
}

程序测试

有解:


无解:


  • 6
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
八数码问题是一种经典的搜索问题,它可以使用宽度优先搜索算法进行求解。下面是使用C语言实现的八数码问题的宽度优先算法解决方法。 首先,定义一个8个元素的数组,用于表示八数码问题的初始状态。例如,下面的代码表示了一个八数码问题的初始状态。 ```c int start[3][3] = {{1, 2, 3}, {4, 5, 6}, {0, 7, 8}}; ``` 其中,0表示空白格子。 接下来,定义一个节点结构体,用于保存每一个状态的信息。节点包含了当前状态的数组、父节点指针和操作符等信息。 ```c struct node { int state[3][3]; struct node *parent; char op; }; ``` 然后,定义一个队列,用于保存所有的状态节点。初始时,将初始状态节点加入队列中。 ```c struct node *queue[10000]; int head = 0, tail = 0; struct node *startNode = (struct node *)malloc(sizeof(struct node)); memcpy(startNode->state, start, sizeof(start)); startNode->parent = NULL; startNode->op = '\0'; queue[tail++] = startNode; ``` 接下来,使用while循环进行循环搜索。每次循环取出队列头部的节点,对其进行扩展操作。扩展操作包括上下左右四个方向的移动。如果移动后的状态是合法的,将其保存为一个新的节点,并加入队列中。如果移动后的状态是目标状态,则搜索结束。 ```c while (head < tail) { struct node *p = queue[head++]; if (memcmp(p->state, target, sizeof(target)) == 0) { printf("find solution\n"); break; } int x, y; for (x = 0; x < 3; x++) { for (y = 0; y < 3; y++) { if (p->state[x][y] == 0) { break; } } if (y < 3) { break; } } if (x > 0) { struct node *newNode = (struct node *)malloc(sizeof(struct node)); memcpy(newNode->state, p->state, sizeof(p->state)); newNode->state[x][y] = newNode->state[x-1][y]; newNode->state[x-1][y] = 0; newNode->parent = p; newNode->op = 'u'; queue[tail++] = newNode; } if (x < 2) { struct node *newNode = (struct node *)malloc(sizeof(struct node)); memcpy(newNode->state, p->state, sizeof(p->state)); newNode->state[x][y] = newNode->state[x+1][y]; newNode->state[x+1][y] = 0; newNode->parent = p; newNode->op = 'd'; queue[tail++] = newNode; } if (y > 0) { struct node *newNode = (struct node *)malloc(sizeof(struct node)); memcpy(newNode->state, p->state, sizeof(p->state)); newNode->state[x][y] = newNode->state[x][y-1]; newNode->state[x][y-1] = 0; newNode->parent = p; newNode->op = 'l'; queue[tail++] = newNode; } if (y < 2) { struct node *newNode = (struct node *)malloc(sizeof(struct node)); memcpy(newNode->state, p->state, sizeof(p->state)); newNode->state[x][y] = newNode->state[x][y+1]; newNode->state[x][y+1] = 0; newNode->parent = p; newNode->op = 'r'; queue[tail++] = newNode; } } ``` 如果搜索结束后,找到了目标状态,可以通过遍历父节点指针,获取到从初始状态到目标状态的移动路径。 完整代码如下: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> struct node { int state[3][3]; struct node *parent; char op; }; int start[3][3] = {{1, 2, 3}, {4, 5, 6}, {0, 7, 8}}; int target[3][3] = {{1, 2, 3}, {4, 5, 6}, {7, 8, 0}}; void printState(int state[3][3]) { int i, j; for (i = 0; i < 3; i++) { for (j = 0; j < 3; j++) { printf("%d ", state[i][j]); } printf("\n"); } printf("\n"); } int main() { struct node *queue[10000]; int head = 0, tail = 0; struct node *startNode = (struct node *)malloc(sizeof(struct node)); memcpy(startNode->state, start, sizeof(start)); startNode->parent = NULL; startNode->op = '\0'; queue[tail++] = startNode; while (head < tail) { struct node *p = queue[head++]; if (memcmp(p->state, target, sizeof(target)) == 0) { printf("find solution\n"); struct node *q = p; while (q) { printState(q->state); q = q->parent; } break; } int x, y; for (x = 0; x < 3; x++) { for (y = 0; y < 3; y++) { if (p->state[x][y] == 0) { break; } } if (y < 3) { break; } } if (x > 0) { struct node *newNode = (struct node *)malloc(sizeof(struct node)); memcpy(newNode->state, p->state, sizeof(p->state)); newNode->state[x][y] = newNode->state[x-1][y]; newNode->state[x-1][y] = 0; newNode->parent = p; newNode->op = 'u'; queue[tail++] = newNode; } if (x < 2) { struct node *newNode = (struct node *)malloc(sizeof(struct node)); memcpy(newNode->state, p->state, sizeof(p->state)); newNode->state[x][y] = newNode->state[x+1][y]; newNode->state[x+1][y] = 0; newNode->parent = p; newNode->op = 'd'; queue[tail++] = newNode; } if (y > 0) { struct node *newNode = (struct node *)malloc(sizeof(struct node)); memcpy(newNode->state, p->state, sizeof(p->state)); newNode->state[x][y] = newNode->state[x][y-1]; newNode->state[x][y-1] = 0; newNode->parent = p; newNode->op = 'l'; queue[tail++] = newNode; } if (y < 2) { struct node *newNode = (struct node *)malloc(sizeof(struct node)); memcpy(newNode->state, p->state, sizeof(p->state)); newNode->state[x][y] = newNode->state[x][y+1]; newNode->state[x][y+1] = 0; newNode->parent = p; newNode->op = 'r'; queue[tail++] = newNode; } } return 0; } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值