HDU1430 BFS + 打表 + 康托展开

  题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1430 , 一道比较好的题。

  这道题要用到很多知识,康托展开、BFS、打表的预处理还要用到一一映射,做完受益匪浅。

  其实这道题也可以用双向BFS来写,思路也已经有了,过几天再来写。

  本文持续更新。



先说搜索部分:

  对于魔板的每一个状态,都可以进行A、B、C三种操作,所以按照图论来讲,就是操作前的状态可以到达操作后的状态,所以就这样转换成了广搜问题。

  这里要注意一点,由于题目要求字典序最小的,所以搜索的时候要按照ABC的顺序来。

再说康托展开:

  康托展开其实就是哈希的一种,即用一个数字来表示一个排列。比如说{A , B , C , D}的全排列中,ABCD对应的康托展开的值为0,ABDC对应的康托展开值为1...

  关于康托展开算法,具体见:http://blog.csdn.net/zhongkeli/article/details/6966805

关于打表预处理:

  由于魔板的所有状态都可以转换为“12345678”,所以这时就需要做一个映射:每组数据都有一个起始状态与目标状态,可以把起始状态用一种映射关系映射为“12345678”,然后用这种映射关系再去改一下终止状态。例如:初态为“12653487” , 目态为“12345678” ;这时映射后初态为“12345678”,即f[1] = 1 , f[2] = 2 , f[6] = 3 , f[5] = 4 , f[3] = 5 , f[4] = 6 , f[8] = 7 , f[7] = 8 ,按照这种映射关系目态应为“12564387”。代码应为:f[start[i] - ‘0‘] = i ; end[i] = f[end[i] - ‘0‘] + ‘0‘;

  有这样一个映射前提,就可以先用BFS预处理从“12345678”到其余所有状态的步骤,然后输入每组测试数据后进行转换,然后这时候就变成了求从“12345678”到映射后的目标状态的步骤的问题,这时按照存好的路径输出即可。

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 = 50000 + 5;
int vis[maxn];
string ans[maxn];

int fac[]={1 , 1 , 2 , 6 , 24 , 120 , 720 , 5040 , 40320};
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_A(string &str)
{
    for(int i = 0 ; i < 4 ; i++)
        swap(str[i] , str[7 - i]);
}
void move_B(string &str)
{
    for(int i = 3 ; i > 0 ; i--)
        swap(str[i] , str[i - 1]);
    for(int i = 4 ; i < 7 ; i++)
        swap(str[i] , str[i + 1]);
}
void move_C(string &str)
{
    char tmp = str[6];
    str[6] = str[5];
    str[5] = str[2];
    str[2] = str[1];
    str[1] = tmp;
}
void BFS(string str)
{
    memset(vis , 0 , sizeof(vis));
    queue <string> que;
    que.push(str);
    int x = Cantor(str);
    vis[x] = 1;
    ans[x] = "";
    while(!que.empty()) {
        string u = que.front();
        que.pop();
        int i = Cantor(u);

        string tmp = u;
        move_A(tmp);
        int k = Cantor(tmp);
        if(!vis[k]) {
            vis[k] = 1;
            que.push(tmp);
            ans[k] = ans[i] + ‘A‘;
        }

        tmp = u;
        move_B(tmp);
        k = Cantor(tmp);
        if(!vis[k]) {
            vis[k] = 1;
            que.push(tmp);
            ans[k] = ans[i] + ‘B‘;
        }

        tmp = u;
        move_C(tmp);
        k = Cantor(tmp);
        if(!vis[k]) {
            vis[k] = 1;
            que.push(tmp);
            ans[k] = ans[i] + ‘C‘;
        }
    }
}
int main()
{
    int a[10];
    string s , e;
    string start = ("12345678");
    BFS(start);
    while(cin >> s >> e)
    {
        for(int i = 0 ; i < 8 ; i++)
            a[s[i] - ‘0‘] = i + 1;
        for(int i = 0 ; i < 8 ; i++)
            e[i] = a[e[i] - ‘0‘] + ‘0‘;
        int k = Cantor(e);
        cout << ans[k] << endl;
    }
    return 0;
}

  

时间: 2024-10-15 03:36:19

HDU1430 BFS + 打表 + 康托展开的相关文章

HDU 1043 Eight(反向BFS+打表+康托展开)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1043 题目大意:传统八数码问题 解题思路:就是从“12345678x”这个终点状态开始反向BFS,将各个状态记录下来,因为数字太大所以用康托展开将数字离散化. 代码: 1 #include<iostream> 2 #include<algorithm> 3 #include<cstdio> 4 #include<cstring> 5 #include<st

HDU 3567 Eight II 打表,康托展开,bfs,g++提交可过c++不可过 难度:3

http://acm.hdu.edu.cn/showproblem.php?pid=3567 相比Eight,似乎只是把目标状态由确定的改成不确定的,但是康托展开+曼哈顿为h值的A*和IDA*都不过,而且也不好控制字典序 换个角度想,虽然起始状态有很多,但是到底哪一位是1,哪一位是2不是最重要的,最重要的是和目标状态对应,所以可以把起始状态重新编码为"12345678"这种形式(先不考虑X),然后目标状态也对应过去,当考虑X的时候,我们可以认为起始状态只有9种,分别是'X'在各个位置的

HDU 1043 Eight (BFS&#183;八数码&#183;康托展开)

题意  输出八数码问题从给定状态到12345678x的路径 用康托展开将排列对应为整数  即这个排列在所有排列中的字典序  然后就是基础的BFS了 #include <bits/stdc++.h> using namespace std; const int N = 5e5, M = 9; int x[4] = { -1, 1, 0, 0}; int y[4] = {0, 0, -1, 1}; int fac[] = {1, 1, 2, 6, 24, 120, 720, 5040, 40320

hdoj1043 Eight(逆向BFS+打表+康拓展开)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1043 思路: 由于自己对康拓展开用的太少,看到这个题没想到康拓展开,最开始打算直接转换为数字,但太占内存了,又想到可以将状态存进set,后来查了一下发现原来是考察康拓展开.另外就是需要打表预处理,这样快很多.BFS部分就是已知终点,从终点逆向搜索,并存每个状态的上一个状态以及操作,以便输出. 坑点:输入是多组输入,POJ那道题才是一组输入,卡在这一上午T_T. 有一组输入为12345678x,需要特

Aizu 0121 Seven Puzzle (康托展开+bfs)

Seven Puzzle Time Limit : 1 sec, Memory Limit : 65536 KB 7パズルは8つの正方形のカードとこれらのカードがぴたりと収まる枠を使って行います.それぞれのカードは互いに区別できるように.0,1,2....7と番号がつけられています.枠には.縦に2個.横に4個のカードを並べることができます. 7パズルを始めるときには.まず枠にすべてのカードを入れます.枠のなかで0のカードだけは.上下左右に隣接するカードと位置を交換することができます.たとえば.枠

hdu1430魔板(广搜+康托展开+string应用)

魔板 Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 2420    Accepted Submission(s): 511 Problem Description 在魔方风靡全球之后不久,Rubik先生发明了它的简化版——魔板.魔板由8个同样大小的方块组成,每个方块颜色均不相同,可用数字1-8分别表示.任一时刻魔板的状态可用方块的颜色

hdu 1430 (BFS 康托展开 或 map )

第一眼看到这题就直接BFS爆搜,第一发爆了内存,傻逼了忘标记了,然后就改,咋标记呢. 然后想到用map函数,就8!个不同的排列,换成字符串用map标记.然后又交一发果断超时,伤心,最恨超时,还不如来个wa算了. 然后卡着了,后来上网上搜了,要用康托展开,康托展开是什么鬼?然后学习了一下,就是个映射,感觉和map差不多. http://blog.csdn.net/zhongkeli/article/details/6966805这个学习一下康托展开. 其实本题的关键不是康托展开,而是置换. 以12

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 &

POJ 1077 Eight(康托展开+BFS)

Eight Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 30176   Accepted: 13119   Special Judge Description The 15-puzzle has been around for over 100 years; even if you don't know it by that name, you've seen it. It is constructed with 15