论久违的八数码问题——小试牛刀(2)

八数码问题

八数码问题也称为九宫问题。在3×3的棋盘,摆有八个棋子,每一个棋子上标有1至8的某一数字,不同棋子上标的数字不同样。棋盘上另一个空格,与空格相邻的棋子能够移到空格中。要求解决的问题是:给出一个初始状态和一个目标状态,找出一种从初始转变成目标状态的移动棋子步数最少的移动步骤。所谓问题的一个状态就是棋子在棋盘上的一种摆法。棋子移动后,状态就会发生改变。解八数码问题实际上就是找出从初始状态到达目标状态所经过的一系列中间过渡状态。——摘自DALAO笔记

{http://www.tuicool.com/articles/QnQ7Z3}

身为一个蒟蒻,能想到的第一个方法就是BFS。BFS在这道题里可谓是如鱼得水,边界清晰加上数据范围小,直接暴力也不是不无可能,只需要判重,避免同一节点访问多次即可。当然,判重可以有不同的方法,比如STL中的SET,HASH,以及简单判重。由于STL使用简单快捷,所以蒟蒻就写了个set判重的函数。

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<set>
using namespace std;
typedef int state[9];
const int maxs=1000000;
state st[maxs],goal;
int dist[maxs];
const int dx[]={-1,1,0,0};
const int dy[]={0,0,-1,1};
set<int> vis;
void lookup()
{
    vis.clear();
 }
 int tangguoqiang(int s)
 {
     int v=0;
     for(int i=1;i<=9;i++)
     {
         v=v*10+st[s][i];
     }
     if(vis.count(v)) return 0;
     vis.insert(v);
     return 1;
 }
int hehe()
{
    lookup();
    int front=1,rear=2;
    while(front<rear)
    {
        state& s=st[front];
        if(memcmp(goal,s,sizeof(s))==0)     return front;
        int z;
        for(z=0;z<9;z++) if(!s[z]) break;
            int x=z/3,y=z%3;
            for(int d=0;d<4;d++)
            {
                int newx=x+dx[d];
                int newy=y+dy[d];
                int newz=newx*3+newy;
                if(newx>=0&&newx<3&&newy>=0&&newy<3)
                {
                    state& t=st[rear];
                    memcpy(&t,&s,sizeof(s));
                    t[newz]=s[z];
                    t[z]=s[newz];
                    dist[rear]=dist[front]+1;
                    if(tangguoqiang(rear)) rear++;
                }
            }
        front++;
    }
    return 0;
 } 

 int main()
 {
     for( int i=0;i<9;i++)
     {
     scanf("%d",&st[1][i]);
     }
    for(int i=0;i<9;i++)
    {
        scanf("%d",&goal[i]);
    }
         int ans=hehe();
         if(ans>0) printf("%d\n",dist[ans]);
         else printf("-1\n");
         return 0;
 }

在时间上可以用memcmp和memcpy来比较整个内存和复制整个内存,相比于循环复制快了许多。(函数在cstring中)。

关于第一个函数,起到了一个初始化的作用,便于管理;第二个函数(唐国强什么的都是乱取名)用来判重,set里是自动排序所以非常方便。

//由于我没有随手写注释的习惯,可能代码阅读起来有些困难,dalao和jvruo不要打我啊呀呀………………

时间: 2024-12-28 02:32:20

论久违的八数码问题——小试牛刀(2)的相关文章

1225 八数码难题

1225 八数码难题 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 题解 查看运行结果 题目描述 Description Yours和zero在研究A*启发式算法.拿到一道经典的A*问题,但是他们不会做,请你帮他们.问题描述 在3×3的棋盘上,摆有八个棋子,每个棋子上标有1至8的某一数字.棋盘中留有一个空格,空格用0来表示.空格周围的棋子可以移到空格中.要求解的问题是:给出一种初始布局(初始状态)和目标布局(为了使题目简单,设目标状态为123804765

HDU 1043 Eight八数码解题思路(bfs+hash 打表 IDA* 等)

题目链接 https://vjudge.net/problem/HDU-1043 经典的八数码问题,学过算法的老哥都会拿它练搜索 题意: 给出每行一组的数据,每组数据代表3*3的八数码表,要求程序复原为初始状态 思路: 参加网站比赛时拿到此题目,因为之前写过八数码问题,心中暗喜,于是写出一套暴力bfs+hash,结果TLE呵呵 思路一:bfs+hash(TLE) 1 #include <cstdio> 2 #include <cstring> 3 #include <queu

洛谷【P1379】八数码难题

P1379 八数码难题 题目描述 在3×3的棋盘上,摆有八个棋子,每个棋子上标有1至8的某一数字.棋盘中留有一个空格,空格用0来表示.空格周围的棋子可以移到空格中.要求解的问题是:给出一种初始布局(初始状态)和目标布局(为了使题目简单,设目标状态为123804765),找到一种最少步骤的移动方法,实现从初始布局到目标布局的转变. 输入输出格式 输入格式: 输入初试状态,一行九个数字,空格用0表示 输出格式: 只有一行,该行只有一个数字,表示从初始状态到目标状态需要的最少移动次数(测试数据中无特殊

八数码三种用时差距极大的写法

进化史,一种比一种长,一种比一种快.不过第三种似乎还不是最终形态. 第一种,傻逼级迭代加深. 去年十一月写的,那时候刚刚学迭代加深,敲了一个钟头才敲完,codevs上直接过,就没太管,觉得这是个水题.实际上呢,看后文. 1 #include<algorithm> 2 #include<iostream> 3 #include<cstring> 4 #include<cstdio> 5 using namespace std; 6 int sx,sy,lim,

八数码的八境界 [转载]

八数码的八境界   研究经典问题,空说不好,我们拿出一个实际的题目来演绎.八数码问题在北大在线测评系统中有一个对应的题,题目描述如下: Eight Time Limit: 1000MS    Memory Limit: 65536K  Special Judge Description The 15-puzzle has been aroundfor over 100 years; even if you don't know it by that name, you've seen it. I

【转】八数码问题及A*算法

一.八数码问题八数码问题也称为九宫问题.在3×3的棋盘,摆有八个棋子,每个棋子上标有1至8的某一数字,不同棋子上标的数字不相同.棋盘上还有一个空格,与空格相邻的棋子可以移到空格中.要求解决的问题是:给出一个初始状态和一个目标状态,找出一种从初始转变成目标状态的移动棋子步数最少的移动步骤.所谓问题的一个状态就是棋子在棋盘上的一种摆法.棋子移动后,状态就会发生改变.解八数码问题实际上就是找出从初始状态到达目标状态所经过的一系列中间过渡状态.八数码问题一般使用搜索法来解.搜索法有广度优先搜索法.深度优

HDU 3567 Eight II(八数码 II)

p.MsoNormal { margin: 0pt; margin-bottom: .0001pt; text-align: justify; font-family: Calibri; font-size: 10.5000pt } h1 { margin-top: 5.0000pt; margin-bottom: 5.0000pt; text-align: center; font-family: 宋体; color: rgb(26,92,200); font-weight: bold; fo

cdoj 1380 Xiper的奇妙历险(2) [八数码问题 bfs + 预处理]

快要NOIP 2016 了,现在已经停课集训了.计划用10天来复习以前学习过的所有内容.首先就是搜索. 八数码是一道很经典的搜索题,普通的bfs就可求出.为了优化效率,我曾经用过康托展开来优化空间,甚至还用过A*来优化时间.不过这道题懒得写了,就一个普普通通的bfs,再加上一个stl 的map就水过了. 首先题目要求有多达10000组数据,依次搜索肯定是不行的,我试过用A*来写,第2组数据就会T掉,所以我们考虑用一个预处理.从末尾状态搜索所有可行的状态,并用一个map来存储答案.然后就很好写了.

BFS(八数码) POJ 1077 || HDOJ 1043 Eight

题目传送门1 2 题意:从无序到有序移动的方案,即最后成1 2 3 4 5 6 7 8 0 分析:八数码经典问题.POJ是一次,HDOJ是多次.因为康托展开还不会,也写不了什么,HDOJ需要从最后的状态逆向搜索,这样才不会超时.判重康托展开,哈希也可. POJ //#include <bits/stdc++.h> #include<iostream> #include<algorithm> #include<string> #include<stack