hiho一下 第一百周 #1312 : 搜索三·启发式搜索 【康托展开-压缩】

#1312 : 搜索三·启发式搜索

时间限制: 10000ms
单点时限: 1000ms
内存限制: 256MB
描述

在小Ho的手机上有一款叫做八数码的游戏,小Ho在坐车或者等人的时候经常使用这个游戏来打发时间。

游戏的棋盘被分割成3x3的区域,上面放着标记有1~8八个数字的方形棋子,剩下一个区域为空。

游戏过程中,小Ho只能移动棋子到相邻的空区域上。当小Ho将8个棋子都移动到如下图所示的位置时,游戏就结束了。

小Hi:小Ho,你觉得如果用计算机来玩这个游戏应该怎么做?

小Ho:用计算机来玩么?我觉得应该是搜索吧,让我想一想。

提示:启发式搜索

输入

第1行:1个正整数t,表示数据组数。1≤t≤8。

接下来有t组数据,每组数据有3行,每行3个整数,包含0~8,每个数字只出现一次,其中0表示空位。

输出

第1..t行:每行1个整数,表示该组数据解的步数。若无解输出"No Solution!"

样例输入
3
1 2 3
4 5 6
7 8 0
1 2 3
4 5 6
8 7 0
8 0 1
5 7 4
3 6 2
样例输出
0
No Solution!
25




代码:

#include<cstdio>
#include<queue>
#include<cstring>
#include<algorithm>
using namespace std;
struct node{
    int shu[3][3],x,y,step;
    bool friend operator < (node xx,node yy)
    {
        return xx.step>yy.step;
    }
}now,qian;
int ans,a[3][3];
int p[9];
int nn[9];
bool fafe[400000];
bool pan(node xx)
{
    int lp=1;
    for (int i=0;i<3;i++)
        for (int j=0;j<3;j++)
            if (xx.shu[i][j]!=lp++)
            return false;
    return true;
}
void ss()
{
    nn[0]=1;
    for (int i=1;i<9;i++)
        nn[i]=nn[i-1]*i;
    return ;
}
int biao(int shu[3][3])
{
    int lp=0;
    for (int i=0;i<3;i++)
        for (int j=0;j<3;j++)
            p[lp++]=shu[i][j];
    int s[8]={0};
    for (int i=0;i<8;i++)
        for (int j=i+1;j<9;j++)
            if (p[i]>p[j])
            s[i]++;
    int ans=0;
    for (int i=0;i<8;i++)
        ans+=s[i]*nn[8-i];
    if (fafe[ans])
        return false;
    fafe[ans]=true;
    return true;
}
void dfs(int x,int y)
{
    for (int i=0;i<3;i++)
        for (int j=0;j<3;j++)
            now.shu[i][j]=a[i][j];
    now.step=0;
    now.x=x;now.y=y;
    memset(fafe,false,sizeof(fafe));
    biao(now.shu);
    priority_queue<node > que;
    que.push(now);
    while (!que.empty())
    {
        qian=que.top();
        que.pop();
        x=qian.x;y=qian.y;
        if (pan(qian))
        {
            ans=qian.step;
            return ;
        }
        if (x+1<3)
        {
            now=qian;
            now.shu[x][y]=now.shu[x+1][y];
            now.shu[x+1][y]=9;
            now.x=x+1;now.y=y;
            if (biao(now.shu))
            {
                now.step=qian.step+1;
                que.push(now);
            }
        }
        if (x-1>=0)
        {
            now=qian;
            now.shu[x][y]=now.shu[x-1][y];
            now.shu[x-1][y]=9;
            now.x=x-1;now.y=y;
            if (biao(now.shu))
            {
                now.step=qian.step+1;
                que.push(now);
            }
        }
        if (y+1<3)
        {
            now=qian;
            now.shu[x][y]=now.shu[x][y+1];
            now.shu[x][y+1]=9;
            now.x=x;now.y=y+1;
            if (biao(now.shu))
            {
                now.step=qian.step+1;
                que.push(now);
            }
        }
        if (y-1>=0)
        {
            now=qian;
            now.shu[x][y]=now.shu[x][y-1];
            now.shu[x][y-1]=9;
            now.x=x;now.y=y-1;
            if (biao(now.shu))
            {
                now.step=qian.step+1;
                que.push(now);
            }
        }
    }
}
void slove()
{
    for (int i=0;i<3;i++)
        for (int j=0;j<3;j++)
            scanf("%d",&a[i][j]);
    ans=-1;
    for (int i=0;i<3;i++)
    {
        for (int j=0;j<3;j++)
            if (a[i][j]==0)
            {
                a[i][j]=9;
                dfs(i,j);
            }
    }
    if (ans==-1)
        printf("No Solution!\n");
    else
        printf("%d\n",ans);
}
int main()
{
    ss();
    int t;scanf("%d",&t);
    while (t--)
        slove();

    return 0;
}




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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值