经典的八数码问题

问题描述:

在一个3*3的方棋盘上放置着1,2,3,4,5,6,7,8八个数码,每个数码占一格,且有一个空格。这些数码可以在棋盘上移动,其移动规则是:与空格相邻的数码方格可以移入空格。现在的问题是:对于指定的初始棋局和目标棋局,给出数码的移动序列。该问题称八数码难题或者重排九宫问题。


问题思路:

这可以看做是一个隐式图搜索问题,把每一次移动一格子的分布认为是一个状态图,空格记为0,并认为移动格子的时候,移动的是0这一个格子和另外的格子交换。我在这里使用典型的BFS算法来判断是否能到达目标状态,并且给出多少步。

#include<iostream>
#include<algorithm>
#include<cstring>
#include<set>

using namespace std;

typedef int state[9];
const int maxn=1000000;
state st[maxn],goal;

int dist[maxn];
int front,rear;
const int dx[]={-1,1,0,0};
const int dy[]={0,0,-1,1};

set<int> vis;

int try_to_insert(int pos)//判断重复
{
    int tmp=0;
    for(int i=0;i<9;i++) tmp=tmp*10+st[pos][i];//把状态图计算为一个9位的独一无二的数字存在set中
    if(vis.count(tmp)) return 0;
    vis.insert(tmp);
    return 1;
}

int bfs()
{
    vis.clear();
    front=1,rear=2;
    while(front<rear)
    {
        state &s=st[front];
        if(memcmp(goal,s,sizeof(s))==0) return front;
        int i,j,x,y;
        for(i=0;i<9;i++) if(s[i]==0) break;//找到0这一格所在位置,把状态的变化看作是0这一格的移动
        x=i/3,y=i%3;
        for(j=0;j<4;j++)
        {
            int newx=x+dx[j];
            int newy=y+dy[j];
            if(newx>=0&&newx<3&&newy>=0&&newy<3)
            {
                state &v=st[rear];
                memcpy(&v,&s,sizeof(s));
                v[x*3+y]=v[newx*3+newy];
                v[newx*3+newy]=0;
                dist[rear]=dist[front]+1;
                if(try_to_insert(rear)) rear++;//判断是否出现重复状态
            }
        }
        front++;
    }
}

int main()
{
    for(int i=0;i<9;i++) cin>>st[1][i];
    for(int i=0;i<9;i++) cin>>goal[i];
    int d=bfs();
    if(d>0) cout<<dist[d]<<endl;
    else cout<<"-1"<<endl;
    return 0;
}

输入:

2 6 4 1 3 7 0 5 8
8 1 5 7 3 6 4 0 2

输出:

31


  • 1
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值