蓝桥杯 历届试题 九宫重排 (八数码问题--康托展开去重 + bfs搜索)

题意:

简单的八数码问题:

给你两个状态 求最少步数。

可以把点变成9:

这样,9个数都不一样,相当于是阶乘的排列。

直接用bfs 搜索 康托展开去重即可。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cctype>
#include <cmath>
#include <cstdlib>
#include <queue>

#define Siz(x) (int)x.size()
#define get(x) (3.1415926*4*x*x*x/3.0)
using namespace std;
typedef long long LL;

const double pi = 3.1415926;
const double eps = 1e-12;

const int dx[] = {1,-1,0,0};
const int dy[] = {0,0,-1,1};


bool vis[400000];
int JIE[10];


void init(){
    JIE[0] = 1;
    for (int i = 1; i <= 9; ++i) JIE[i] = JIE[i-1] * i;


//    printf("%d\n", JIE[9]);
}
char hs[10];



int HASH(int x){
    int tx = x;
    for (int i = 0; i < 9; ++i){
        hs[8-i] = tx % 10;
        tx /= 10;
    }
    int sum = 0;
    for (int i = 0; i < 9; ++i){
        int t = 0;
        for (int j = i + 1; j < 9; ++j){
            if (hs[j] < hs[i])++t;
        }
        sum += JIE[8-i] * t;
    }
    return sum;
}

char st[10], ed[10];

queue<int>q;
int dp[400000];
char s[10];
int a[5][5];
int bfs(int sv,int ev){

    int hashsv = HASH(sv);
    q.push(sv);
    vis[hashsv] = 1;
    while(!q.empty()){
        int u = q.front(); q.pop();
        if (u == ev) return dp[HASH(ev)];
        int tu = u;
        for (int i = 0; i < 9; ++i) {
            s[8-i] = tu % 10 + 48;
            tu /= 10;
        }
        int x,y;
        for (int i = 0; i < 9; ++i){
            a[i/3  ][i%3 ] = s[i] - 48;

            if (s[i] == '9'){
                x = i/3;
                y = i % 3;
            }
        }

        for (int i = 0; i < 4; ++i){
            int xx = dx[i] + x;
            int yy = dy[i] + y;
            if (xx < 0 || yy < 0 || xx >2 || yy > 2) continue;

            swap(a[xx][yy],a[x][y] );
            int nxt = 0;
            for (int j = 0; j < 3; ++j){
                for (int k = 0; k < 3; ++k){
                    nxt = nxt * 10 + a[j][k];
                }
            }
            swap(a[xx][yy], a[x][y]);
            int hashnxt = HASH(nxt);
            if (!vis[hashnxt]){
                vis[hashnxt] = 1;
                q.push(nxt);
                dp[hashnxt] = dp[HASH(u)] + 1;
            }
        }
    }

    return -1;
}


int main(){
    init();


    scanf("%s%s",st,ed);
    for (int i = 0; i < 9; ++i){
        if (st[i] == '.') st[i] = '9';
        if (ed[i] == '.') ed[i] = '9';
    }

    int sv = 0, ev = 0;
    for (int i = 0; i < 9; ++i){
        sv = sv * 10 + st[i] - 48;
        ev = ev * 10 + ed[i] - 48;
    }
    int ans = bfs(sv,ev);
    printf("%d\n",ans);
    return 0;
}


  历届试题 九宫重排   时间限制:1.0s   内存限制:256.0MB        
问题描述   如下面第一个图的九宫格中,放着 1~8 的数字卡片,还有一个格子空着。与空格子相邻的格子中的卡片可以移动到空格中。经过若干次移动,可以形成第二个图所示的局面。

《蓝桥杯 历届试题 九宫重排 (八数码问题--康托展开去重 + bfs搜索)》
《蓝桥杯 历届试题 九宫重排 (八数码问题--康托展开去重 + bfs搜索)》

  我们把第一个图的局面记为:12345678.

  把第二个图的局面记为:123.46758

  显然是按从上到下,从左到右的顺序记录数字,空格记为句点。

  本题目的任务是已知九宫的初态和终态,求最少经过多少步的移动可以到达。如果无论多少步都无法到达,则输出-1。 输入格式   输入第一行包含九宫的初态,第二行包含九宫的终态。 输出格式   输出最少的步数,如果不存在方案,则输出-1。 样例输入 12345678.

123.46758 样例输出 3 样例输入 13524678.

46758123. 样例输出 22  

  历届试题 九宫重排   时间限制:1.0s   内存限制:256.0MB        
问题描述   如下面第一个图的九宫格中,放着 1~8 的数字卡片,还有一个格子空着。与空格子相邻的格子中的卡片可以移动到空格中。经过若干次移动,可以形成第二个图所示的局面。

《蓝桥杯 历届试题 九宫重排 (八数码问题--康托展开去重 + bfs搜索)》
《蓝桥杯 历届试题 九宫重排 (八数码问题--康托展开去重 + bfs搜索)》

  我们把第一个图的局面记为:12345678.

  把第二个图的局面记为:123.46758

  显然是按从上到下,从左到右的顺序记录数字,空格记为句点。

  本题目的任务是已知九宫的初态和终态,求最少经过多少步的移动可以到达。如果无论多少步都无法到达,则输出-1。 输入格式   输入第一行包含九宫的初态,第二行包含九宫的终态。 输出格式   输出最少的步数,如果不存在方案,则输出-1。 样例输入 12345678.

123.46758 样例输出 3 样例输入 13524678.

46758123. 样例输出 22  

    原文作者:九宫格问题
    原文地址: https://blog.csdn.net/aozil_yang/article/details/70304367
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞