八数码问题完全版-是否可解判断及求解

2023-05-16

/*
八数码问题
有一个3*3的棋盘,其中有0-8 9个数字,0表示空格,其他的数字可以和0交换位置。求由初始状态
1 2 3
4 5 6
7 8 0
到达目标状态步数最少的解。

其典型算法是广度优先搜索,具体算法是:
struct 类名 m_ar[可能结点数];
int h,r
main()
{
    h=0;r=1;
    while ((h<r)&&(r<可能结点数))
    {
        if (判断每一种可能性,如果某一种操作符合要求)
        {
            将m_ar[h]操作后记录于m_ar[r];
            如果和目标一样,输出结果并中止程序;
            r=r+1;
        }
        h=h+1;
    }
    表示没有结果。
}

***********************************
是否可解的判断
我知道什么样的情况有解,什么情况没解.
函数f(s)表示s前比s小的数字的数目.
例如:
|1 3 4|
|2 8 6|
|5 7 |
表示成:
|1 3 4|2 8 6|5 7 X| 则f(7)=6, f(5)=4,f(6)=4,f(8)=4,f(2)=1,
f(4)=2,f(3)=1,f(1)=0
当f(a8)+f(a7)+……+f(a1)为偶数时才能重排成
所以嘛,上面那个有解的.
下面我就来证明一下.

 

设任意一种情况:
|a1 a2 a3|
|a4 a5 a6|
|a7 a8 X | (X表示空格)

将之放在一行上: |a1 a2 a3|a4 a5 a6|a7 a8 X |
数字的上下移动可以相对于是空格的上下移动.
所以我们只要讨论X的移动了:

假设函数f(s)表示s前比s小的数字的数目.
例如:|1 3 4|2 8 6|5 7 X| 则f(7)=6, f(5)=4, f(8)=4,……

对于X在同一行中的移动,f(a8)+f(a7)+……+f(a1)大小不变(*1)
如:|a1 a2 a3|a4 a5 a6|a7 a8 X |=>|a1 a2 a3|a4 a5 a6|a7 X a8|

对于X在列中移动是,我们不妨设X与a6对换(即a6下移一格)
则数列变为|a1 a2 a3|a4 a5 X|a7 a8 a6|,可能引起变化的f(s)只有f(a6),f(a7),f(a8)
讨论:有4种情况1) a6<a7, a6<a8
f(a8) 减小1
f(a7) 减小1
f(a6) 不变
所以f(a8)+f(a7)+……+f(a1)奇偶性不变.
2) a6<a7, a6>a8
f(a8) 不变
f(a7) 减小1
f(a6) 增大1
所以f(a8)+f(a7)+……+f(a1)奇偶性不变.
3) a6>a7, a6>a8
f(a8) 不变
f(a7) 不变
f(a6) 增大2
所以f(a8)+f(a7)+……+f(a1)奇偶性不变.
3) a6>a7, a6<a8
f(a8) 减小1
f(a7) 不变
f(a6) 增大1
所以f(a8)+f(a7)+……+f(a1)奇偶性不变.

这样,再将a3下移一格则|a1 a2 a3|a4 a5 X|a7 a8 a6|=>|a1 a2 X|a4 a5 a3|a7 a8 a6|
则同样,对可能变化的f(a3),f(a4),f(a5)讨论,情况一上面完全一样。

其它情况都如此:
如:|a1 X a3|a4 a5 a6|a7 a8 a2|=>|a1 a5 a3|a4 X a6|a7 a8 a2|
就f(a3),f(a4),f(a5)变化.

结论:因为对于|1 2 3|4 5 6| 7 8 X|, f(8)+f(7)+……+f(1)=28, 是偶数,
所以当f(a8)+f(a7)+……+f(a1)为偶数时才能重排成|1 2 3|4 5 6| 7 8 X|成功.

*/
#include <stdio.h>
#include <conio.h>
#include <string.h>

typedef unsigned long long  UINT64;
typedef struct
{
    char    x;                  //位置x和位置y上的数字换位
    char    y;                  //其中x是0所在的位置
} EP_MOVE;

#define SIZE        3           //8数码问题,理论上本程序也可解决15数码问题,
#define NUM         SIZE * SIZE //但move_gen需要做很多修改,输入初始和结束状态的部分和check_input也要修改
#define MAX_NODE    1000000
#define MAX_DEP     100

#define XCHG(a, b)  { a=a + b; b=a - b; a=a - b; }
#define TRANS(a, b) { long    iii; (b)=0; for(iii=0; iii < NUM; iii++) (b)=((b) << 4) + a[iii]; }   //将数组a转换为一个64位的整数b
#define RTRANS(a, b) /
    { /
        long    iii; /
        UINT64  ttt=(a); /
        for(iii=NUM - 1; iii >= 0; iii--) /
        { /
            b[iii]=ttt & 0xf; /
            ttt>>=4; /
        } /
    }   //将一个64位整数a转换为数组b

//
typedef struct  EP_NODE_Tag
{
    UINT64              v;  //保存状态,每个数字占4个二进制位,可解决16数码问题
    struct EP_NODE_Tag  *prev;  //父节点
    struct EP_NODE_Tag  *small, *big;
} EP_NODE;

EP_NODE m_ar[MAX_NODE];
EP_NODE *m_root;
long    m_depth;                //搜索深度
EP_NODE m_out[MAX_DEP];         //输出路径

//
long move_gen(EP_NODE *node, EP_MOVE *move)
{
    long    pz;     //0的位置
    UINT64  t=0xf;
    for(pz=NUM - 1; pz >= 0; pz--)
    {
        if((node->v & t) == 0)
        {
            break;  //找到0的位置
        }

        t<<=4;
    }

    switch(pz)
    {
        case 0:
            move[0].x=0;
            move[0].y=1;
            move[1].x=0;
            move[1].y=3;
            return 2;
        case 1:
            move[0].x=1;
            move[0].y=0;
            move[1].x=1;
            move[1].y=2;
            move[2].x=1;
            move[2].y=4;
            return 3;
        case 2:
            move[0].x=2;
            move[0].y=1;
            move[1].x=2;
            move[1].y=5;
            return 2;
        case 3:
            move[0].x=3;
            move[0].y=0;
            move[1].x=3;
            move[1].y=6;
            move[2].x=3;
            move[2].y=4;
            return 3;
        case 4:
            move[0].x=4;
            move[0].y=1;
            move[1].x=4;
            move[1].y=3;
            move[2].x=4;
            move[2].y=5;
            move[3].x=4;
            move[3].y=7;
            return 4;
        case 5:
            move[0].x=5;
            move[0].y=2;
            move[1].x=5;
            move[1].y=4;
            move[2].x=5;
            move[2].y=8;
            return 3;
        case 6:
            move[0].x=6;
            move[0].y=3;
            move[1].x=6;
            move[1].y=7;
            return 2;
        case 7:
            move[0].x=7;
            move[0].y=6;
            move[1].x=7;
            move[1].y=4;
            move[2].x=7;
            move[2].y=8;
            return 3;
        case 8:
            move[0].x=8;
            move[0].y=5;
            move[1].x=8;
            move[1].y=7;
            return 2;
    }

    return 0;
}

/* */
long move(EP_NODE *n1, EP_MOVE *mv, EP_NODE *n2)    //走一步,返回走一步后的结果
{
    char    ss[NUM];
    RTRANS(n1->v, ss);
    XCHG(ss[mv->x], ss[mv->y]);
    TRANS(ss, n2->v);
    return 0;
}

/* */
long add_node(EP_NODE *node, long r)
{
    EP_NODE *p=m_root;
    EP_NODE *q;
    while(p)
    {
        q=p;
        if(p->v == node->v)
            return 0;
        else if(node->v > p->v)
            p=p->big;
        else if(node->v < p->v)
            p=p->small;
    }

    m_ar[r].v=node->v;
    m_ar[r].prev=node->prev;
    m_ar[r].small=NULL;
    m_ar[r].big=NULL;
    if(node->v > q->v)
    {
        q->big= &m_ar[r];
    }
    else if(node->v < q->v)
    {
        q->small= &m_ar[r];
    }

    return 1;
}

/*
得到节点所在深度
*/
long get_node_depth(EP_NODE *node)
{
    long    d=0;
    while(node->prev)
    {
        d++;
        node=node->prev;
    }

    return d;
}

/*
返回值:成功-返回搜索节点数,节点数不够-(-1),无解-(-2)
*/
long bfs_search(char *begin, char *end)
{
    long    h=0, r=1, c, i, j;
    EP_NODE l_end, node, *pnode;
    EP_MOVE mv[4];                      //每个局面最多4种走法
    TRANS(begin, m_ar[0].v);
    TRANS(end, l_end.v);
    m_ar[0].prev=NULL;
    m_root=m_ar;
    m_root->small=NULL;
    m_root->big=NULL;
    while((h < r) && (r < MAX_NODE - 4))
    {
        c=move_gen(&m_ar[h], mv);
        for(i=0; i < c; i++)
        {
            move(&m_ar[h], &mv[i], &node);
            node.prev= &m_ar[h];
            if(node.v == l_end.v)
            {
                pnode= &node;
                j=0;
                while(pnode->prev)
                {
                    m_out[j]=*pnode;
                    j++;
                    pnode=pnode->prev;
                }

                m_depth=j;
                return r;
            }

            if(add_node(&node, r)) r++; //只能对历史节点中没有的新节点搜索,否则会出现环
        }

        h++;
        printf("/rSearch...%9d/%d @ %d", h, r, get_node_depth(&m_ar[h]));
    }

    if(h == r)
    {
        return -2;
    }
    else
    {
        return -1;
    }
}

/* */
long check_input(char *s, char a, long r)
{
    long    i;
    for(i=0; i < r; i++)
    {
        if(s[i] == a - 0x30) return 0;
    }

    return 1;
}

/* */
long check_possible(char *begin, char *end)
{
    char    fs;
    long    f1=0, f2=0;
    long    i, j;
    for(i=0; i < NUM; i++)
    {
        fs=0;
        for(j=0; j < i; j++)
        {
            if((begin[i] != 0) && (begin[j] != 0) && (begin[j] < begin[i])) fs++;
        }

        f1+=fs;
        fs=0;
        for(j=0; j < i; j++)
        {
            if((end[i] != 0) && (end[j] != 0) && (end[j] < end[i])) fs++;
        }

        f2+=fs;
    }

    if((f1 & 1) == (f2 & 1))
        return 1;
    else
        return 0;
}

/* */
void output(void)
{
    long    i, j, k;
    char    ss[NUM];
    for(i=m_depth - 1; i >= 0; i--)
    {
        RTRANS(m_out[i].v, ss);
        for(j=0; j < SIZE; j++)
        {
            for(k=0; k < SIZE; k++)
            {
                printf("%2d", ss[SIZE * j + k]);
            }

            printf("/n");
        }

        printf("/n");
    }
}

/* */
int main(void)
{
    char    s1[NUM];
    char    s2[NUM];
    long    r;
    char    a;
    printf("Input begin status:");
    r=0;
    while(r < NUM)
    {
        a=getch();
        if(a >= 0x30 && a < 0x39 && check_input(s1, a, r))
        {
            s1[r++]=a - 0x30;
            printf("%c", a);
        }
    }

    printf("/nInput end status:");
    r=0;
    while(r < NUM)
    {
        a=getch();
        if(a >= 0x30 && a < 0x39 && check_input(s2, a, r))
        {
            s2[r++]=a - 0x30;
            printf("%c", a);
        }
    }

    printf("/n");
    if(check_possible(s1, s2))
    {
        r=bfs_search(s1, s2);
        printf("/n");
        if(r >= 0)
        {
            printf("search depth=%d, nodes=%ld/n", m_depth, r);
            output();
        }
        else if(r == -1)
        {
            printf("Not enouph nodes searched./n");
        }
        else if(r == -2)
        {
            printf("No way to do that./n");
        }
        else
        {
            printf("Unknown error./n");
        }
    }
    else
    {
        printf("Mission impossible!/n");
    }

    return 0;
}

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

八数码问题完全版-是否可解判断及求解 的相关文章

  • 第三章实验

    第一题 span class token keyword class span span class token class name Student span span class token punctuation span span
  • 洛谷P1025 数的划分(DFS+剪枝)

    题目描述 将整数 nn 分成 kk 份 xff0c 且每份不能为空 xff0c 任意两个方案不相同 xff08 不考虑顺序 xff09 例如 xff1a n 61 7n 61 7 xff0c k 61 3k 61 3 xff0c 下面三种分
  • Armbian 更换清华大学源

    修改 sources list 文件 sudo nano etc apt sources list 把官方源前面加上 号注释掉 xff0c 最下面加上下面的清华大学源列表 清华大学源 deb https mirrors tuna tsing
  • sem_wait sem_post信号量操作进本函数

    sem wait sem post 信号量的数据类型为结构sem t xff0c 它本质上是一个长整型的数 函数sem init xff08 xff09 用来初始化一个信号量 它的原型为 xff1a extern int sem init
  • Windows下重启Linux子系统(WSL)

    Linux子系统 xff08 WSL xff09 是基于 LxssManager 服务运行的 重启WSL的话只需要将 LxssManager 重启即可 命令重启 以管理员权限运行cmd命令即可 停止LxssManager服务 net sto
  • Mac安装dmg程序提示无可装载的文件系统

    安装dmg程序是提示 无可装在的文件系统 1 查看SIP状态 在终端中输入csrutil status xff0c 就可以看到是 enabled 还是 disabled 2 关闭SIP 重启MAC xff0c 按住commond 43 R直
  • windows恶意软件删除工具 MRT.EXE

    MRT 是微软自Windows7开始就自带的一款绿色的恶意软件删除工具 具体路径为C WINDOWS system32 MRT exe 默认已经在系统环境变量中 所以我们直接 win 43 R 输入 mrt 即可运行 操作也极其简单 xff
  • BitLocker正在等待激活,怎样可以关闭?

    问题 xff1a 装完win10系统后有时候会显示 BitLocker正在等待激活 一直有个黄色的小锁图标看着有些头疼 xff0c 怎样才能取消启用Bitlocker呢 xff0c 也没有关闭的按钮 处理方法 控制面板 在 Bitlocke
  • PROXMOX 开源虚拟服务器系统安装及配置

    前言 说到学习Linux xff0c 在适应图形化界面后 xff0c 我们逐渐可以通过一些shell命令来操作Linux系统 xff0c 此时何曾不想多尝试几个不同的Linux系统 xff0c 但是每每安装配置虚拟机又很麻烦 xff0c 如
  • Deepin 深度操作系统安装教程

    简介 深度操作系统 deepin 是一个致力于为全球用户提供美观易用 安全稳定服务的Linux发行版 xff0c 同时也一直是排名最高的来自中国团队研发的Linux发行版 xff0c 下面我们开始从下载镜像到安装系统一步步进行讲解 系统下载
  • 香橙派 OrangPi PC 安装Lakka游戏系统及使用指南

    香橙派 Orange Pi PC Orange Pi PC 采用了全志四核A7高性能处理器Allwinner H3 xff0c 集成以太网 DC电源输入 视频 音频输出等接口 xff0c 支持HDMI AVOUT视频输出等功能 尽管体积很小
  • 我把华为云的Ubuntu 18.04升级到了Ubuntu 22.04

    华为云建站有些年头了 xff0c 当时装的是ubuntu18 04 xff0c 停止维护更新日期是2023年4月 xff0c 只剩半年时间就该停服了 xff0c 这么看来是时候升级以下系统版本了 xff0c 不然升级版本都可能会有问题 由于
  • Ubuntu Budgie 22.04 设置中文语言并安装拼音输入法

    之前将ubuntu server 22 04 安装了 Budgie Desktop 桌面环境 xff0c 系统语言是英文的 xff0c 如果要作为桌面使用还有些不适应 xff0c 我们要如何将系统语言切换为中文并支持中文输入呢 xff1f
  • OpenKylin常用软件安装

    由于OpenKylin仍处于测试阶段 xff0c 应用商店软件并不全 xff0c 所以很多软件的安装非常麻烦 xff0c 以下列出了一些常用软件的安装方法 需要的童鞋可以直接复制命令后进行安装 xff0c 安装软件需要使用root权限 xf
  • 利用sourceinsight宏(Quicker.em)提高编码效率和质量

    利用sourceinsight宏 Quicker em 提高编码效率和质量 Marco是sourceinsight软件一个强大的功能 xff0c 用户可以通过编写宏来实现自定义功能 这里有个比较流行的宏文件quicker em xff0c
  • Git Clone 报错 `SSL certificate problem: unable to get local issuer certificate`

    如果您在尝试克隆Git存储库时得到 SSL certificate problem unable to get local issuer certificate 的错误 这意味着Git无法验证远程存储库的SSL证书 如果SSL证书是自签名的
  • 树莓派从源码构建安装Git最新版

    1 查看Git版本 首先我们通过SSH客户端连接树莓派 在树莓派中通过查看 Git 版本信息 xff0c 我们只能看到最高版本显示为 2 30 2 xff0c 并且通过apt安装也无法将Git更新到最新版 git version sudo
  • linux安装部署免费confluence wiki

    Centos7安装部署免费confluence wiki 知识库 详细操作步骤 前言 xff1a confluence是团队协作软件 xff0c 改变团队工作方式 xff0c 作为现代化办公不可缺少的工具 wiki所需的安装包 xff1a
  • 对printf源码的分析

    对printf源码的分析 一 printf的源码如下 span class token macro property span class token directive keyword include span span class to
  • iPhone开发:可拉伸的图片

    还记得在Windows下用MFC或WTL写用户界面程序的时候 xff0c 为了给可改变大小的对话框加上背景图案 xff0c 需要对设计师提供的图片进行裁剪 把图片切成九块 xff0c 其中四个角是不拉伸的 xff0c 四条棱边可以在一个方向

随机推荐

  • 解决在KDE桌面环境WebStorm不能输入中文问题

    由于jetbrains官方包的问题 xff0c Fcitx5输入法文字候选托盘暂时不能更改 xff0c 如有最新解决办法 xff0c 可查看ArchWiki官方 xff0c 或者查看jetbrains官方 排查错误 cat etc loca
  • NAS如何使用SnapShot快照功能?

    Snapshot是基于Btrfs文件系统产生的快速备份和还原数据的第三方应用 xff0c 利用Snapshot为数据提供保护 xff0c 以防止因意外删除 应用程序崩溃 数据损毁和病毒所造成的数据丢失 1 TOS应用中心 xff0c 找到S
  • 备份电脑不求人,"时间机器"轻松备份你的Mac

    相比Windows 自带的系统还原功能 xff0c Mac有内置的Time Machine功能 xff0c 可以方便我们进行整机备份 xff0c 在关键时刻成为你重要数据的一颗 后悔药 xff01 Time Machine xff08 时间
  • NESTJS 服务化架构设计和项目搭建

    创建项目很简单 xff0c nest cli一键创建 xff0c 关键是如何基于nestjs现有能力进行架构设计 架构设计 项目背景 项目涉及的底层数据全部来自于公司的一个公共服务 jsf xff0c 该公共服务可对接口进行发布和订阅 xf
  • 视频转码 ffmpeg hevc to h264

    通过ffmpeg将hevc编码的MP4视频转码为h264编码 fmpeg i inputfile map 0 c a copy c s copy c v libx264 output mp4 顺带旋转角度也调整为0 参考 xff1a htt
  • linux下查看进程的状态 /proc/[pid]/status

    查看进程的状态 xff1a 1 查看进程的pid xff0c 以java为例 xff1a ps ef grep java 2 查看进程状态 xff1a cat proc pid status 关键字 linux root 64 localh
  • paho.mqtt.cpp交叉编译

    开发板 rk3288 43 lubuntu 16 04 主机 Ubuntu16 04 编译之前可能要安装一些软件 xff0c 可参考paho mqtt cpp文档 xff1a https github com eclipse paho mq
  • mosquitto-1.6.10 交叉编译

    openssl 1 0 2l tar gz mosquitto 1 6 10 tar gz 由于mosquitto 1 6 10版本较新 xff0c 需要选择openssl 1 0 2及较新版本 1 openssl span class t
  • C/C++ 简单debug宏函数

    span class token comment debug h span span class token macro property span class token directive hash span span class to
  • ubuntu 18.04 LTS 安装Qt qtcreator 、example

    https www cnblogs com SendBoringBackToNoWhere p 15050359 html sudo apt install qtcreator qt5 default qtbase5 examples qt
  • ubuntu 文件系统自动挂载U盘后是只读文件问题

    安装 ntfs 3g exfat fuse xff0c 之后重新挂载 apt get install ntfs 3g exfat fuse 重新挂载
  • mt7688 OpenWrt 编译

    一 OpenWrt源码下载 虚拟机 xff1a Ubuntu 16 04 LTS sudo apt install git subversion curl wget gawk git clone https git openwrt org
  • mysql trigger 使用以及与 sqlite3 trigger 比较

    一 触发事件的表与触发更新的表使用同一个表 使用情景 xff0c 表里的某行数据发生update时自动更新修改时间 updated sqlite3 3 40 0 MariaDB 10 10 2 对应 MySQL 8 1 sqlite3 up
  • 1.Linux中超频及cpufreq相关汇总

    1 蛤蟆笔记UNIX高级编程 cpufreq相关汇总 其中一些内容摘自网络 xff0c 此处蛤蟆根据自己阅读习惯和理解进行了一些汇总整理 随着 energyefficient computing 和 performance per watt
  • 双尺度与多尺度图像细节提升 python matlab

    双尺度图像分解细节提升 一副图像经过大尺度的均值滤波 公式10 后得到大尺度的基础层Bn xff0c 然后用原图减去大尺度基础层 公式11 可以得到一副小尺度的细节层Dn xff0c 然后加上原图In xff0c 图像细节得到提升 xff0
  • WSL关闭与windows的互交互(解决PATH等环境变量问题

    如果在windows和wsl中都安装了nodejs 那么由于wsl的互交互特性 npm的运行就会不太正常 以下是禁用互交互的步骤 在WSL的终端中输入 span class token keyword echo span span clas
  • 数据结构——树

    1 树的相关定义 xff08 1 xff09 树 xff1a 包含n xff08 n gt 0 xff09 个节点的有穷集合 xff0c 其中每个元素称为节点 xff08 node xff09 xff1b 有一个特定的节点被称为根节点或树根
  • Qt QImage图片透明设置(Thinkvd开发日志)

    开发Thinkvd中的player 设置透明度用的是sdl来实现的 xff0c 转换中的水印用的是png 如何设置水印的透明度 xff0c 实际上要求把图片转换成带alpha的32位即可 实现代码 xff1a 8 void ImageCom
  • 关于 win10 系统安装Geomagic Wrap 2017导致一直蓝屏重启解决方案

    学校进行专业实训 xff0c 开了一门3D打印的课程 老师要求下载Geomagic Wrap 2017 xff0c 但是凡是win10系统安装的人都出现了不同程度的蓝屏 xff0c 我的电脑更是一直蓝屏重启 xff0c 网上找了很多方法 x
  • 八数码问题完全版-是否可解判断及求解

    八数码问题 有一个3 3的棋盘 xff0c 其中有0 8 9个数字 xff0c 0表示空格 xff0c 其他的数字可以和0交换位置 求由初始状态 1 2 3 4 5 6 7 8 0 到达目标状态步数最少的解 其典型算法是广度优先搜索 xff