HDU1043 Eight

戏子无情 提交于 2020-01-20 19:14:28

题目链接:https://vjudge.net/problem/HDU-1043

简单介绍一下八数码问题:
在一个3×3的九宫格上,填有1~8八个数字,空余一个位置,例如下图:
在这里插入图片描述
在上图中,由于右下角位置是空的,你可以移动数字,比如可以将数字6下移一位:

在这里插入图片描述

1~8按顺序排列的情况称为“初始状态”(如最上方图)。“八数码问题”即是求解对于任意的布局,将其移动至“初始状态”的方法。
给定一个现有的九宫格布局,请输出将它移动至初始状态的移动方法的步骤。

输入:

输入包含多组数据,处理至文件结束。每组数据占一行,包含8个数字和表示空位的‘x’,各项以空格分隔,表示给定的九宫格布局。
在这里插入图片描述

输出:

对于每组输入数据,输出一行,即移动的步骤。向上、下、左、右移动分别用字母u、d、l、r表示;如果给定的布局无法移动至“初始 状态”,请输出unsolvable。
如果有效的移动步骤有多种,输出任意即可。

思路:
双向BFS,简单来说就是同时进行两个BFS,但每个BFS的vis数组有了新的用途即判断另一个BFS是否达到此BFS扩展到的此刻的点,若抵达即连通。

unsolvable的情况用逆序数的奇偶性判断,因为目标状态12345678逆序数为0,所以当前态的逆序数必为偶

用康托展开记录字典序用于状态压缩(hash)

#include<iostream>
#include<sstream>
#include<cstdio>
#include<cstdlib>
#include<string>
#include<cstring>
#include<algorithm>
#include<functional>
#include<iomanip>
#include<numeric>
#include<cmath>
#include<queue>
#include<vector>
#include<set>
#include<cctype>
#define PI acos(-1.0)
const int INF = 0x3f3f3f3f;
const int NINF = -INF - 1;
typedef long long ll;
using namespace std;
int fac[10] = {1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880};
int vis1[362885], vis2[362885];
int eda[9]={ 1, 2, 3, 4, 5, 6, 7, 8, 0};
string path[362885];
int dx[4] = {1, -1, 0, 0}, dy[4] = {0, 0, -1, 1};
char p1[4] = {'d', 'u', 'l', 'r'}, p2[4] = {'u', 'd', 'r', 'l'};
struct node
{
    int s[9];
    int cur, n;//cur目前x所在位置,n为hash值
}st;
int cantor(int *s)//康托展开
{
    int sum = 1;
    for (int i = 0;i < 9; ++i)
    {
        int k = 0;
        for (int j = i + 1; j < 9; ++j)
            if( s[j] < s[i]) k++;
        sum += k * fac[8 - i];
    }
    return sum;
}
void bfs()
{
    memset(vis1, 0, sizeof(vis1));
    memset(vis2, 0, sizeof(vis2));
    queue<node> q1, q2;
    st.n = cantor(st.s);
    q1.push(st);
    vis1[st.n] = 1;
    path[st.n] = "";//重要
    node ed;
    memcpy(ed.s, eda, sizeof(ed.s));
    ed.n = cantor(ed.s);
    ed.cur = 8;
    path[ed.n] = "";
    q2.push(ed);
    vis2[ed.n] = 1;
    while (q1.size() || q2.size())
    {
        node temp1 = q1.front();
        q1.pop();
        int x1 = temp1.cur / 3, y1 = temp1.cur % 3;
        for (int i = 0; i < 4; ++i)
        {
            int nx = x1 + dx[i], ny = y1 + dy[i];
            if (nx < 0 || nx > 2 || ny < 0 || ny > 2) continue;
            node rec = temp1;
            rec.cur = nx * 3 + ny;
            swap(rec.s[temp1.cur], rec.s[rec.cur]);
            rec.n = cantor(rec.s);
            if (vis2[rec.n])
            {
                reverse(path[rec.n].begin(), path[rec.n].end());
                cout << path[temp1.n] << p1[i] << path[rec.n] << endl;
                return;
            }
            if (!vis1[rec.n])
            {
                vis1[rec.n] = 1;
                path[rec.n] = path[temp1.n];
                path[rec.n] += p1[i];
                q1.push(rec);
            }
        }
        node temp2 = q2.front();
        q2.pop();
        int x2 = temp2.cur / 3, y2 = temp2.cur % 3;
        for (int i = 0; i < 4; ++i)
        {
            int nx = x2 + dx[i], ny = y2 + dy[i];
            if (nx < 0 || nx > 2 || ny < 0 || ny > 2) continue;
            node rec = temp2;
            rec.cur = nx * 3 + ny;
            swap(rec.s[temp2.cur], rec.s[rec.cur]);
            rec.n = cantor(rec.s);
            if (vis1[rec.n])
            {
                reverse(path[temp2.n].begin(), path[temp2.n].end());
                cout << path[rec.n] << p2[i] << path[temp2.n] << endl;
                return;
            }
            if (!vis2[rec.n])
            {
                vis2[rec.n] = 1;
                path[rec.n] = path[temp2.n];
                path[rec.n] += p2[i];
                q2.push(rec);
            }
        }
    }
}

int main()
{
    char c;
    while(cin >> c)
    {
        if(c == 'x')
        {
            st.s[0] = 0;
            st.cur = 0;
        }
        else st.s[0] = c - '0';
        for (int i = 1; i < 9; ++i)
        {
            cin >> c;
            if ( c == 'x')
            {
                st.s[i] = 0;
                st.cur = i;
            }
            else st.s[i] = c - '0';
        }
        int k = 0;
        for(int i = 0; i < 8; ++i)
        {
            if (st.s[i])
            {
                for (int j = i + 1; j < 9; ++j)
                    if (st.s[j] < st.s[i] && st.s[j]) k++;
            }
        }
        if(k & 1) cout<< "unsolvable" << endl;
        else bfs();
    }
    return 0;
}
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!