HDU1043 八数码(BFS + 打表)

  题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1043 , 康托展开 + BFS + 打表。

  经典八数码问题,传说此题不做人生不完整,关于八数码的八境界:http://www.cnblogs.com/goodness/archive/2010/05/04/1727141.html

  我自己是用哈希(康托展开) + BFS  + 打表过的,第三重境界。

  由于一些高级的搜索现在还没学,所以目前能升级的也就是用双向BFS来做了,等过几天有心情了来做。

  本文长期更新。



算法:  

  由于此题是求某个起始状态到“12345678X”的步骤,所以可以考虑先求出“12345678X”的所有变换的步骤,即打表预处理。

  这里要注意就是最后输出的时候,由于我们求得是逆序,所以要倒序输出,倒序输出的时候要注意‘u‘、‘d‘、‘l‘、‘r‘都应该颠倒过来,比如说你从A状态向上变换为B状态,这时你从B变为A就要向下变换。

  这里哈希还是用的康托展开,这个问题我在上一篇博客中有提到过。

BFS + 打表:

#include <iostream>
#include <cstdio>
#include <vector>
#include <queue>
#include <cmath>
#include <string>
#include <string.h>
#include <algorithm>
using namespace std;
#define LL __int64
#define eps 1e-8
#define INF 1e8
#define lson l , m , rt << 1
#define rson m + 1 , r , rt << 1 | 1
const int MOD = 2333333;
const int maxn = 362880;
bool vis[maxn];
string ans[maxn];
int fac[]={1 , 1 , 2 , 6 , 24 , 120 , 720 , 5040 , 40320 , 362880};

int Cantor(string str)
{
    int ret = 0;
    int n = str.size();
    for(int i = 0 ; i < n ; i++) {
        int cnt = 0;
        for(int j = i ; j < n ; j++)
            if(str[j] < str[i])
                cnt++;
        ret += cnt * fac[n - i - 1];
    }
    return ret;
}
void move_Up(string &str , int pos)
{
    swap(str[pos] , str[pos - 3]);
}
void move_Down(string &str , int pos)
{
    swap(str[pos] , str[pos + 3]);
}
void move_Left(string &str , int pos)
{
    swap(str[pos] , str[pos - 1]);
}
void move_Right(string &str , int pos)
{
    swap(str[pos] , str[pos + 1]);
}
void BFS(string start)
{
    memset(vis , 0 , sizeof(vis));
    queue <string> que;
    que.push(start);
    int x = Cantor(start);
    vis[x] = 1;
    ans[x] = "";
    int pos;
    while(!que.empty()) {
        string u = que.front();
        que.pop();
        int i = Cantor(u);
        for(pos = 0 ; pos < 9 ; pos++)
            if(u[pos] == ‘x‘)
                break;

        if(pos > 2) {
            string tmp = u;
            move_Up(tmp , pos);
            int k = Cantor(tmp);
            if(!vis[k]) {
                vis[k] = 1;
                que.push(tmp);
                ans[k] = ans[i] + ‘u‘;
            }
        }
        if(pos < 6) {
            string tmp = u;
            move_Down(tmp , pos);
            int k = Cantor(tmp);
            if(!vis[k]) {
                vis[k] = 1;
                que.push(tmp);
                ans[k] = ans[i] + ‘d‘;
            }
        }
        if(pos % 3 != 0) {
            string tmp = u;
            move_Left(tmp , pos);
            int k = Cantor(tmp);
            if(!vis[k]) {
                vis[k] = 1;
                que.push(tmp);
                ans[k] = ans[i] + ‘l‘;
            }
        }
        if(pos % 3 != 2) {
            string tmp = u;
            move_Right(tmp , pos);
            int k = Cantor(tmp);
            if(!vis[k]) {
                vis[k] = 1;
                que.push(tmp);
                ans[k] = ans[i] + ‘r‘;
            }
        }
    }
}
int main()
{
    char ch[30];
    string start = "12345678x";
    BFS(start);
    while(gets(ch))
    {
        string str = "";
        for(int i = 0 ; ch[i] != ‘\0‘ ; i++) {
            if(ch[i] == ‘ ‘)
                continue;
            else
                str += ch[i];
        }
        int k = Cantor(str);
        if(vis[k]) {
            for(int i = ans[k].size() - 1 ; i >= 0 ; i--) {
                if(ans[k][i] == ‘u‘)
                    putchar(‘d‘);
                else if(ans[k][i] == ‘d‘)
                    putchar(‘u‘);
                else if(ans[k][i] == ‘l‘)
                    putchar(‘r‘);
                else
                    putchar(‘l‘);
            }
            puts("");
        } else {
            cout << "unsolvable" << endl;
        }
    }
    return 0;
}
时间: 2024-10-28 17:38:52

HDU1043 八数码(BFS + 打表)的相关文章

poj 1077 八数码(BFS+康托展开)

1 /* 2 题意:八数码问题,给出3*3的矩阵含1~8以及x,给出一个符合的解使得移动后的矩阵的顺序为1~8,最后为x 3 4 题解:BFS 5 需要用到康托展开来表示状态,不然数组无法完全表示所有状态,这样BFS就无法判断找不到解的情况(status 6 的0ms,0KB究竟是怎么做到的,简直不能想象=.=) 7 */ 8 #include <cstdio> 9 #include <cstring> 10 #include <queue> 11 #include &

code1225 八数码Bfs

Bfs搜索 1.把棋盘直接作为状态: #include<iostream> #include<cstring> #include<queue> #include<cstdlib> using namespace std; const int n=9; const int Size=4; int flag; struct Point{ int x,y; }; struct Node{ int board[Size][Size]; Point space; in

luogu_1379 八数码难题

八数码-->BFS+set 1 #include<iostream> 2 #include<cstdlib> 3 #include<cstdio> 4 #include<cstring> 5 #include<set> 6 using namespace std; 7 struct aaa{ 8 int map[4][4]; 9 int dep,x,y; 10 }que[370000]; 11 set<int> ssr; 12

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

ACM/ICPC算法训练 之 BFS-广搜进阶-八数码(经典)(POJ1077+HDU1043)

八数码问题也称为九宫问题.(本想查查历史,结果发现居然没有词条= =,所谓的历史也就不了了之了) 在3×3的棋盘,摆有八个棋子,每个棋子上标有1至8的某一数字,不同棋子上标的数字不相同.棋盘上还有一个空格,与空格相邻的棋子可以移到空格中.要求解决的问题是: 给出一个初始状态和一个目标状态,找出一种从初始转变成目标状态的移动棋子步数最少的移动步骤. 所谓问题的一个状态就是棋子在棋盘上的一种摆法.棋子移动后,状态就会发生改变.解八数码问题就是找出从初状态到目标状态所经过的一系列中间状态.八数码问题一

【算法】BFS+哈希解决八数码问题

15拼图已经有超过100年; 即使你不叫这个名字知道的话,你已经看到了.它被构造成具有15滑动砖,每一个从1到15上,并且所有包装成4乘4帧与一个瓦块丢失.让我们把丢失的瓷砖"X"; 拼图的目的是安排瓷砖以便它们排序为: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15× 这里唯一合法经营是交流'X'与它共享一个边缘的瓷砖之一.作为一个例子,举动下列顺序解决了一个稍微加扰难题: 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 5 6 7 8 5 6

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

八数码问题+路径寻找问题+bfs(隐式图的判重操作)

Δ路径寻找问题可以归结为隐式图的遍历,它的任务是找到一条凑够初始状态到终止问题的最优路径, 而不是像回溯法那样找到一个符合某些要求的解. 八数码问题就是路径查找问题背景下的经典训练题目. 程序框架 process()  初始化vis数组,初始化初始节点到目标节点的移动距离 dfs()搜索到每一个节点,如果不是目标节点,对其依次扩展所有子节点,并判重,全部子节点搜索完全后,改变父节点:如果是目标节点成功返回 输出最少移动步数 input: 2 6 4 1 3 7 0 5 8 8 1 5 7 3 6