IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 游戏开发 -> 八数码 (Astar) -> 正文阅读

[游戏开发]八数码 (Astar)

题目描述

在一个?3×3?的网格中,1~8?这?8个数字和一个?X?恰好不重不漏地分布在这?3×3?的网格中。

例如:

1 2 3
X 4 6
7 5 8

在游戏过程中,可以把?X?与其上、下、左、右四个方向之一的数字交换(如果存在)。

我们的目的是通过交换,使得网格变为如下排列(称为正确排列):

1 2 3
4 5 6
7 8 X

例如,示例中图形就可以通过让?X?先后与右、下、右三个方向的数字交换成功得到正确排列。

交换过程如下:

1 2 3   1 2 3   1 2 3   1 2 3
X 4 6   4 X 6   4 5 6   4 5 6
7 5 8   7 5 8   7 X 8   7 8 X

把?X?与上下左右方向数字交换的行动记录为?udlr

现在,给你一个初始网格,请你通过最少的移动次数,得到正确排列。

输入格式

输入占一行,将?3×33×3?的初始网格描绘出来。

例如,如果初始网格如下所示:

1 2 3 
x 4 6 
7 5 8 

则输入为:1 2 3 x 4 6 7 5 8

输出格式

输出占一行,包含一个字符串,表示得到正确排列的完整行动记录。

如果答案不唯一,输出任意一种合法方案即可。

如果不存在解决方案,则输出?unsolvable

输入样例:

2  3  4  1  5  x  7  6  8 

输出样例

ullddrurdllurdruldr

思路

首先,八数码有解判断的必要条件:逆序对的个数若为偶数个时有解,若为奇数个则无解。详见图(借,有问题则删,https://www.acwing.com/solution/content/35528/)


其次,对于使用astar优化时,因为当我们移动一个点的时候,只能上下左右间移动,因此 f(n) 预估距离的设定,这里定义为当前图各个点到最终图各个点的哈夫曼距离之和。

参考代码:

#include <bits/stdc++.h>

#define io ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)

#define LL long long

#define x first

#define y second

#define PII pair<int,int>

#define PIS pair<int,string>

#define PIII pair<int,PII>

#define PDD pair<double,double>

using namespace std;

const int INF=0x3f3f3f3f;

const int N=1005;

const int M=1e7;

const int mod=1e9+7;

  

/*

    八数码有解判断的必要条件:逆序对的个数若为偶数个时有解,若为奇数个则无解。


*/

  

//当前点到终点的预估距离,每个位置点距离自己正确位置的哈夫曼距离和

// abs(xs-xe)+abs(ys-ye);

int f(string state)

{

    int res = 0;

    int len=state.length();

    for(int i=0;i<len;i++)

    {

        if(state[i] != 'x')

        {

            int t = state[i] - '1';

            res += abs(i/3 - t/3)+abs(i%3 - t%3);

        }

    }

    return res;

}

string start; //存初始状态

int dir[4][2]={-1,0,1,0,0,-1,0,1};

char go[]="udlr";

string astar()

{

    //最终状态

    string end="12345678x";

    map<string , int> dis; //到这个状态的实际距离

    map<string , pair<string,char> >pre; //到这个状态的,前个状态和动作

  

    priority_queue<PIS,vector<PIS>,greater<PIS> >q;

    q.push({f(start),start});

    dis[start]=0;

    while(q.size())

    {

        auto tmp=q.top();

        q.pop();

  

        //当前状态

        string state=tmp.y;

        //到达最终状态,退出

        if(state==end)break;

  

        //获取当前步数

        int step=dis[state];

        int x,y;

        //找到操作"X"的位置

        for(int i=0;i<9;i++)

        {

            if(state[i]=='x')

            {

                x=i/3;

                y=i%3;

                break;

            }

        }

        //存储当前状态

        string source=state;

  

        //开始向4个方向扩展

        for(int i=0,nx,ny;i<4;i++)

        {

            nx=x+dir[i][0];

            ny=y+dir[i][1];

            if(nx<0 || nx>=3 || ny<0 || ny>=3)continue;

  

            //交换2点位置

            swap(state[x*3+y],state[nx*3+ny]);

            /*

                更新状态的2种情况:

                1.若移动后的状态不存在

                2.若移动后的状态所用步数大于当前状态,则表示移动后的状态下都可以被更新

            */

            if(dis.count(state)==0 || dis[state]>step+1)

            {

                //更新实际距离

                dis[state]=step+1;

                //记录前驱,{前一个状态,动作}

                pre[state]={source,go[i]};

                q.push({dis[state]+f(state),state});

            }

  

            //回溯2点位置

            swap(state[x*3+y],state[nx*3+ny]);

        }

    }

  

    //反向遍历操作结果

    string res="";

    while(end!=start)

    {

        res+=pre[end].y;

        end=pre[end].x;

    }

    reverse(res.begin(),res.end());

    return res;

}

int main()

{

     char c;

     string str; //用来判断逆序对

     for(int i=0;i<9;i++)

     {

         cin>>c;

         if(c!='x')str+=c;

         start+=c;

     }

  

     int cnt=0; //逆序对个数

    for(int i=0;i<str.length();i++)

    {

        for(int j=i+1;j<str.length();j++)

        {

            if(str[i]>str[j])cnt++;

        }

    }

    //奇数个,无解

    if(cnt&1)cout<<"unsolvable\n";

    //偶数个,存在解

    else cout<<astar()<<"\n";

  

    system("pause");

    return 0;

}
  游戏开发 最新文章
6、英飞凌-AURIX-TC3XX: PWM实验之使用 GT
泛型自动装箱
CubeMax添加Rtthread操作系统 组件STM32F10
python多线程编程:如何优雅地关闭线程
数据类型隐式转换导致的阻塞
WebAPi实现多文件上传,并附带参数
from origin ‘null‘ has been blocked by
UE4 蓝图调用C++函数(附带项目工程)
Unity学习笔记(一)结构体的简单理解与应用
【Memory As a Programming Concept in C a
上一篇文章      下一篇文章      查看所有文章
加:2022-05-02 13:31:36  更:2022-05-02 13:32:24 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 11:09:50-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码