[codevs1225]八数码难题

本文介绍了一个使用A*算法解决8数码问题的方法。通过定义启发式函数并结合广度优先搜索策略,实现了从任意初始状态到目标状态的最短路径寻找。文章提供了完整的代码实现,并解释了关键步骤。

题目描述 Description
Yours和zero在研究A*启发式算法.拿到一道经典的A*问题,但是他们不会做,请你帮他们.
问题描述

在3×3的棋盘上,摆有八个棋子,每个棋子上标有1至8的某一数字。棋盘中留有一个空格,空格用0来表示。空格周围的棋子可以移到空格中。要求解的问题是:给出一种初始布局(初始状态)和目标布局(为了使题目简单,设目标状态为123804765),找到一种最少步骤的移动方法,实现从初始布局到目标布局的转变。

输入描述 Input Description
输入初试状态,一行九个数字,空格用0表示

输出描述 Output Description
只有一行,该行只有一个数字,表示从初始状态到目标状态需要的最少移动次数(测试数据中无特殊无法到达目标状态数据)

样例输入 Sample Input
283104765

样例输出 Sample Output
4

不加A*也能过,加了跑得贼快
代码bfs,优先取出F[i]较小的点
F[i] = g[i] +h[i],其中g[i]为已走步数,h[i]为不在位的数码个数

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<queue>
using namespace std;
const int MAXN = 15;
int SS[] = {0,1,2,3,8,0,4,7,6,5};
const int M_S = 100000009;

struct zt
{
    int a[MAXN];
    int f;
    int loc;
    int step;
};
bool operator < (zt a,zt b)
{
    return a.f + a.step > b.f + b.step;
}
int F(zt x)
{
    int ans = 0;
    for(int i = 1;i <= 9;i ++)
        if(x.a[i] != SS[i])ans ++;
    return ans;
}
priority_queue <zt> q;
char C[15];
int mu[] = {-1,1,-3,3};
zt x;
bool hash[M_S + 1];
bool can(zt u)
{
    int ans = 0;
    for(int i = 1;i <= 9;i ++)
    {
        ans = ((ans%M_S)*(10%M_S))%M_S;
        ans += u.a[i];
    }
    if(hash[ans])return false;
    hash[ans] = true;
    return true;
}
int main()
{
    scanf("%s",C + 1);

    for(int i = 1;i <= 9;i ++)
    {
        x.a[i] = C[i] - '0';
        if(!x.a[i])x.loc = i;
    }
    x.f = F(x);
    q.push(x);
    while(!q.empty())
    {
        zt u = q.top();
        q.pop();
        for(int i = 0;i <= 3;i ++)
        {
            int loc = u.loc + mu[i];
            if(u.loc <= 3 && mu[i] == -3)
                continue;
            if(u.loc > 6 && mu[i] == 3)
                continue;
            if(u.loc % 3 == 0 && mu[i] == 1)
                continue;
            if(u.loc % 3 == 1 && mu[i] == -1)
                continue;
            zt t = u;
            t.loc = loc;
            swap(t.a[loc],t.a[u.loc]);
            t.f = F(t);
            t.step = u.step + 1;
            if(can(t))q.push(t);
            if(t.f == 0)
            {
                printf("%d",t.step);
                return 0;
            }
        }
    }
    return 0; 
}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值