ACM 1225 八数码难题(A*)

1225 八数码难题

 时间限制: 1 s
 空间限制: 128000 KB
 题目等级 : 钻石 Diamond
题目描述 Description

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

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

输入描述 Input Description

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

输出描述 Output Description

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

样例输入 Sample Input

283104765

样例输出 Sample Output

4

数据范围及提示 Data Size & Hint

详见试题












































A*算法
#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>

using namespace std;

#define INF 9999999
#define MAX_N 10

struct State
{
    char Data[MAX_N];
    int G;
    int H;
};

char strInit[MAX_N];
char strGoal[MAX_N];

vector<State> Opened;
vector<State> Closed;

int dx[]={1,0,-1,0};//右,下,左,上
int dy[]={0,1,0,-1};

int H(const char *strState)
{
    int cnt=0;
    for(int i=0;i<9;i++)
    {
        if(strState[i]!=strGoal[i]) cnt++;
    }

    return cnt;
}

int FindMin()
{
    int mini,minx=INF;
    int sz=Opened.size();
    for(int i=0;i<sz;i++)
    {
        if(minx>Opened[i].G+Opened[i].H)
        {
            mini=i;
            minx=Opened[i].G+Opened[i].H;
        }
    }

    return mini;
}

bool UpdateOpened(State &state)
{
    int sz=Opened.size();

    for(int i=0;i<sz;i++)
    {
        if(!strcmp(state.Data,Opened[i].Data) && state.G<Opened[i].G)
        {
            Opened[i].G=state.G;
            return true;
        }
    }

    return false;
}

bool InClosed(const char *strState)
{
    int sz=Closed.size();
    for(int i=0;i<sz;i++)
    {
        if(!strcmp(strState,Closed[i].Data))
        {
            return true;
        }
    }

    return false;
}

void Expand(State &state)
{
    State tmp;
    int y,x;

    for(int i=0;i<3;i++)
    for(int j=0;j<3;j++)
    {
        if(state.Data[i*3+j]=='0')
        {
            y=i;x=j;
        }
    }

    int nx,ny;
    for(int i=0;i<4;i++)
    {
        nx=x+dx[i];ny=y+dy[i];

        if(nx>=0 && nx<3 && ny>=0 && ny<3)
        {
            strcpy(tmp.Data,state.Data);
            char ch=tmp.Data[ny*3+nx];
            tmp.Data[y*3+x]=ch;
            tmp.Data[ny*3+nx]='0';
            tmp.G=state.G+1;

            if(InClosed(tmp.Data)) continue;
            if(!UpdateOpened(tmp))
            {
                tmp.H=H(tmp.Data);
                Opened.push_back(tmp);
            }
        }
    }
}

int main()
{
    int ans=-1;
    State tmp;

    strcpy(strGoal,"123804765");
    scanf("%s",strInit);

    strcpy(tmp.Data,strInit);
    tmp.G=0;
    tmp.H=H(strInit);
    Opened.push_back(tmp);

    while(!Opened.empty())
    {
        int minID=FindMin();

        tmp=Opened[minID];
        Opened.erase(Opened.begin()+minID);
        Closed.push_back(tmp);

        if(!strcmp(tmp.Data,strGoal))
        {
            ans=tmp.G;
            break;
        }

        Expand(tmp);
    }

    printf("%d\n",ans);

    return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值