CODEVS 1225 八数码难题(BFS && A*)

11 篇文章 0 订阅
2 篇文章 0 订阅

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

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

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

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

样例输入 Sample Input
283104765

样例输出 Sample Output
4

今天上午刚学了Astar算法…下午找炜城大大要了道八数码….结果现在才A。

Astar的估价函数本来就是个玄学的东西…一脸辛酸….哎不说了,先讲题。

好吧我还是说吧…自己想了个比较玄学的估价方式,然后死活WA最后一个点,红太阳a过来把我的估价去了…..然后就AC了,woccccc!

所以,现在我的代码…就是个 堆优化的BFS= =。

这个八数码是直接给你一串数字的…如123458076,要存的话…我选择把状态转化成字符串用hash,(map大法好!)(Orz fluency神犇教我怎么用队列存结构体里的数组)

在BFS的时候,找到当前状态的0格在哪里。然后写一个判断函数,判断一下0格能不能和其他格子交换,如果能的话就swap一下,把当前的棋盘状态压到一个字符串里,如果出现过,就continue掉,没有出现过,那么 ,从开始 到 当前的状态的步数:等于 队首状态步数+1,把当前状态扔堆里。
第一次搜到目标状态,就是最优解。
先留个坑,等我找到了正确的估价方式就来填坑= =。

神T*堆优化(然并卵)过的BFS:

#include<cstdio>
#include<queue> 
#include<map>
#include<iostream>
#include<string>
#include<cstring>
using namespace std;
const int inf=0x7fffffff;
struct heap
{
    int ans;
    int now[5][5];
    bool operator <(const heap &hah)const
    {
        //return ans+h>hah.ans+hah.h;纪念我挂掉的估价函数...
        return ans>hah.ans;
    }
};
map<string,bool>use;
int sum;
priority_queue<heap>q;
int ditu[5][5];
int x1[]={0,1,0,-1,0};
int yy1[]={0,0,1,0,-1};
string haha;
int ans=inf;
bool pd(int i,int j)
{
    if(i>3||i<1||j>3||j<1)
        return false;
    if(!q.top().now[i][j])
        return false; 
    return true;
}
void bfs()
{
    while(!q.empty())
    {
        heap hah=q.top();
        int h=0;
        int x,y;
        for(int i=1;i<=3;i++)
        {
            for(int j=1;j<=3;j++)
            {
                if(!hah.now[i][j])
                    x=i,y=j;//空格
            }   
        }
        heap pre=q.top();
        for(int i=1;i<=4;i++)//枚举四个方向。 
        {
            heap push=pre;
            int xx=x+x1[i];
            int yy=y+yy1[i];
            if(pd(xx,yy))
            {
                string ha="";
                swap(push.now[xx][yy],push.now[x][y]);

                for(int j=1;j<=3;j++)
                {
                    for(int k=1;k<=3;k++)
                    {
                        ha+=(push.now[j][k]+'0');
                    }   
                }
                if(!use[ha])
                {
                    use[ha]=1;              
                    push.ans=pre.ans+1;
                    q.push(push);
                    if(ha==haha)
                    {
                        ans=min(ans,push.ans);
                        return;
                    }
                } 
            }
        }
        q.pop();
    }
}
int hahah[]={0,1,2,3,8,0,4,7,6,5};
void clr()
{
    haha="";
    for(int i=1;i<=3;i++)
    {
        for(int j=1;j<=3;j++)
        {   
            haha+=hahah[j+(i-1)*3]+'0';
            ditu[i][j]=hahah[j+(i-1)*3];
        }
    }//目标串。 
}

int main()
{
    clr(); 
    heap fk;
    string fuk=""; 
    fk.ans=0;
    for(int i=1;i<=3;i++)
    {
        for(int j=1;j<=3;j++)
        {
            char c=getchar();
            fuk+=c;
            fk.now[i][j]=c-'0';
        }//初始串 
    }
    use[fuk]=1;
    q.push(fk);
    bfs();
    printf("%d",ans);
    return 0;
}

Astar代码&&讲解(待补全):

这里写代码片
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值