八数码

P1541 八数码
时间: 1000ms / 空间: 131072KiB / Java类名: Main

背景

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

描述

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

输入格式

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

输出格式

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

测试样例1

输入

283104765

输出

4

#include <stdio.h>
#include <string.h>
#include <queue>

using namespace std;

typedef struct NODE
{
    char str[10];                         //记录搜索的状态
    int pos;                               //记录0的位置
    int step;                              //记录步数
}Node;

int factorial[10] = {1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880};   //阶乘
int mark[362890];
char es[10] = "123804765", ss[10];      //分别记录起始和终结状态

int cuntor(char str[])                  //康拓展开
{
    int i, j, cnt, ans = 0, len;
    len = strlen(str);
    for(i = 0; i < len; i++)
    {
        cnt = 0;
        for(j = i+1; j < len; j++)
        {
            if(str[i] > str[j])
            {
                cnt++;
            }
        }
        ans += cnt*factorial[8-i];
    }
    return ans+1;
}

int bfs()
{
    queue<Node> q;
    int tc;
    mark[cuntor(ss)] = 1;                      //将起始节点放入队列, 并标记
    Node temp, t;
    temp.pos = (strchr(ss, '0')-ss);
    strcpy(temp.str, ss);
    temp.step = 0;
    q.push(temp);
    while(!q.empty())
    {
        temp = q.front();
        q.pop();
        if(!strcmp(temp.str, es))                  //若找到终结状态则返回步数
        {
            return temp.step;
        }

        if(temp.pos/3 != 0)                        //向上移动
        {
            t = temp;
            t.str[t.pos] = t.str[t.pos-3];
            t.str[t.pos-3] = '0';
            tc = cuntor(t.str);                     //注意cuntor数的判重
            if(!mark[tc])
            {
                mark[tc] = 1;
                t.pos = t.pos-3;
                t.step++;
                q.push(t);
            }
        }
        if(temp.pos/3 != 2)                      //向下移动
        {
            t = temp;
            t.str[t.pos] = t.str[t.pos+3];
            t.str[t.pos+3] = '0';
            tc = cuntor(t.str);
            if(!mark[tc])
            {
                mark[tc] = 1;
                t.pos = t.pos+3;
                t.step++;
                q.push(t);
            }
        }
        if(temp.pos%3 != 0)                      //向左移动
        {
            t = temp;
            t.str[t.pos] = t.str[t.pos-1];
            t.str[t.pos-1] = '0';
            tc = cuntor(t.str);
            if(!mark[tc])
            {
                mark[tc] = 1;
                t.pos = t.pos-1;
                t.step++;
                q.push(t);
            }
        }
        if(temp.pos%3 != 2)                       //向右移动
        {
            t = temp;
            t.str[t.pos] = t.str[t.pos+1];
            t.str[t.pos+1] = '0';
            tc = cuntor(t.str);
            if(!mark[tc])
            {
                mark[tc] = 1;
                t.pos = t.pos+1;
                t.step++;
                q.push(t);
            }
        }
    }
    return -1;                                    //若搜不到返回-1
}

int main()
{
    scanf("%s", ss);
    printf("%d\n", bfs());                        //打印结果
    return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值