1. 程式人生 > >【 HDU1043-經典BFS+康拓展開 八數碼】 (待更)

【 HDU1043-經典BFS+康拓展開 八數碼】 (待更)

給定一個序列,由1~8數字和字母x組成,表示的是一個3*3的矩形。每次操作x都能與相鄰的數字交換,問如何操作才能使得序列為{1,2,3,4,5,6,7,8,x}。
 


//多組資料-需要計算全部路徑後直接輸出
//反向搜尋+打表(離線)
#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>
using namespace std;
#define MAX 400000
#define AIM 46234    //123456780對應的康託Hash值
bool v[MAX];
char path[MAX][40];    //總路徑
int len;    //路徑長

/*udlr*/
char *dir = "durl";    //反向搜尋
int mov[4][2] = { { -1, 0 }, { 1, 0 }, { 0, -1 }, { 0, 1 } };
//八數碼狀態結構體
struct Node{
    int s[9];
    int loc;    //空位
    int status;    //Hash值-排列值
    int fa;    //記錄父狀態
    char d;    //到此狀態的移動方向
}n[MAX];
int fac[10] = { 1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880 };
//康託逆展開-返回Hash值
int Inverse_cantor(int s[9])
{
    int sum = 0;
    for (int i = 0; i < 9; i++)
    {
        int num = 0;    //逆序數計數器
        for (int j = i + 1; j < 9; j++)
            if (s[j] < s[i])
                num++;
        sum += num*fac[9 - i - 1];
    }
    return sum + 1;
}
/*反向記錄路徑*/
void count_path(Node end)
{
    int status = end.status;
    int f = end.fa;
    len = 0;
    path[status][len++] = end.d;
    while (f)
    {
        path[status][len++] = n[f].d;//方向記錄
        f = n[f].fa;    //查詢父結點
    }
}
void BFS()
{
    memset(v, 0, sizeof(v));
    Node next;    //下一臨時狀態
    int head = 0, tail = 0;
    /*目標狀態*/
    for (int i = 0; i < 8; i++)
        n[0].s[i] = i + 1;
    n[0].s[8] = 0;
    n[0].loc = 8;
    n[0].status = AIM;
    v[AIM] = true;
    while (head <= tail)    //模擬佇列
    {
        //計算二維座標
        int x = n[head].loc / 3;
        int y = n[head].loc % 3;
        for (int i = 0; i < 4; i++)    //遍歷四方向
        {
            int tx = x + mov[i][0];
            int ty = y + mov[i][1];
            if (tx < 0 || tx>2 || ty < 0 || ty>2)continue;
            //新狀態更新
            next = n[head];
            next.loc = tx * 3 + ty;    //計算新空位
            next.s[n[head].loc] = next.s[next.loc];    //原空位替換
            next.s[next.loc] = 0;    //新空位
            next.fa = head;
            next.d = dir[i];
            next.status = Inverse_cantor(next.s);
            //判重併入隊
            if (!v[next.status])
            {
                v[next.status] = true;
                count_path(next);
                n[++tail] = next;
            }
        }
        head++;
    }
}

int main()
{
    /* BFS-打表 */
    BFS();
    /*input*/
    char ch[3];
    Node cur;
    while (scanf("%s", ch) != EOF)
    {
        if (!strcmp(ch, "x"))
            cur.s[0] = 0, cur.loc = 0;
        else cur.s[0] = ch[0] - '0';
        for (int i = 1; i < 9; i++)
        {
            scanf("%s", ch);
            if (!strcmp(ch, "x"))
                cur.s[i] = 0, cur.loc = i;
            else cur.s[i] = ch[0] - '0';
        }
        cur.status = Inverse_cantor(cur.s);
        
        /*output*/
        if (v[cur.status])
            printf("%s\n", path[cur.status]);
        else
            printf("unsolvable\n");
    }
    return 0;
}

還可以用A*好像