poj 1077 Eight(双方向bfs)

23374 ワード

タイトルリンク:http://poj.org/problem?id=1077
 
構想分析:テーマは最短の移動経路を探し出して、与えられた状態から最終状態に達することを要求する.
<1>探索アルゴリズム選択:最短の移動経路を見つける必要があるためbfs探索を選択
<2>判定方法:
スペースを数字9と見なすと、状態の集合を1-9の配列の組み合わせの集合と見なすことができ、康托展開に基づいて、各状態を正の整数にマッピングすることができる.
ハッシュテーブルで重み付けを行います.
<3>ステータス圧縮:検索時に各ステータスを1~9からなる9桁の数字に変換することで、ステータス圧縮と解凍を行うことができます.
<4>双方向広さ優先検索のテクニック:
1)利点:初期状態とターゲット状態が与えられた問題に対して、双方向検索を使用して検索することができ、空間と時間を節約することができる.
2)双方向広さ優先探索の考え方:双方向広さ優先探索は同時に2種類の探索を開始する;1つの広さ優先探索は、所与の状態からターゲット状態へ探索し、もう1つの広さ優先探索は、ターゲット状態から
指定されたステータスを検索すると、2つのステータスツリーが生成されます.検索時に各ステータスツリーの親ノードと子ノードの関係を記録します.各ステートツリーのルートノードからノードの拡張を開始すると、
のノードが既にステータスツリーに表示されている場合、ノードは拡張されません.拡張されたノードが別のステータスツリーにすでに存在する場合、最初のステータスとターゲットステータス(最短かどうか)を接続するパスが見つかります.
ある状態ツリーには初期状態とその状態との間に1つのパスが存在し、別の状態ツリーにはその状態とターゲット状態との間に1つのパスが存在するため、拡張ノードを接続点とし、
2本のステータスツリーの初期ステータスとターゲットステータスが接続されています. 
 
コードは次のとおりです.
#include <iostream>
#include <cstring>
#include <cmath>
using namespace std;

const int MAX_N = 362880 + 10; // 10! + 10
int set[MAX_N];                //     ,    ,           (0:     1:     2:    )
int map[9];                    //       
char path[MAX_N];              //           
const int FACT[9] = {1, 1, 2, 6, 24, 120, 720, 5040, 40320};
const int MOVE[4][2] = {{0, -1}, {0, 1}, {-1, 0}, {1, 0}};

struct Node
{
    int state_num;
    int pre, next;            //             
    char pre_dir, next_dir;   //                 
}state_queue[MAX_N];

int Canto()
{
    int state_num = 1;
    for (int i = 0; i < 9; ++i)
    {
        int temp = map[i] - 1;

        for (int j = 0; j < i; ++j)
            temp -= (map[j] < map[i]);
        state_num += temp * FACT[8 - i];
    }
    return state_num;
}

void StateNumToMAP(int num)
{
    int i = 8;
    while (num)
    {
        map[i--] = num % 10;
        num /= 10;
    }
}

char MoveDirection(bool forward, int i)
{
    char result = 0;

    if (!forward)
    {
        if (0 <= i && i <= 1)
            i = 1 - i;
        else
            i = 5 - i;
    }

    switch (i)
    {
    case 0: result = 'u'; break;
    case 1: result = 'd'; break;
    case 2: result = 'l'; break;
    case 3: result = 'r'; break;
    }
    return result;
}

int MapToStateNum()
{
    int ans = 0;

    for (int i = 0; i < 9; ++i)
        ans = ans * 10 + map[i];
    return ans;
}

int BFS()
{
    int head, tail, state_canto_val;
    Node start, end;

    head = tail = 1;
    start.state_num = MapToStateNum();
    start.pre = -1;      // -1,      
    start.pre_dir = -1;  //   
    start.next = 0;      // 0      
    start.next_dir = 0;  //   
    state_canto_val = Canto();
    set[state_canto_val] = 1;

    if (start.state_num == 123456789)
        return -2;

    end.state_num = 123456789;
    end.next = -1;      // -1      
    end.next_dir = -1;  //   
    end.pre = 0;        // 0      
    end.pre_dir = 0;    //   

    state_queue[tail++] = start;
    state_queue[tail++] = end;
    set[1] = -2;

    while (head < tail)
    {
        int now_x, now_y, next_x, next_y;
        Node now_state;

        now_state = state_queue[head];
        StateNumToMAP(now_state.state_num);
        state_canto_val = Canto();

        for (int i = 0; i < 9; ++i)
        {
            if (map[i] == 9)
            {
                now_x = i % 3, now_y = i / 3;
                break;
            }
        }
        for (int i = 0; i < 4; ++i)
        {
            int temp_swap;
            Node next_state;

            next_x = now_x;
            next_y = now_y;
            next_x += MOVE[i][0];
            next_y += MOVE[i][1];

            if (next_x < 0 || next_x >= 3
                || next_y < 0 || next_y >= 3)
                continue;
            temp_swap = map[now_x + now_y * 3];
            map[now_x + now_y * 3] = map[next_x + next_y * 3];
            map[next_x + next_y * 3] = temp_swap;

            state_canto_val = Canto();
            if (state_queue[head].pre == 0 && set[state_canto_val] == 0)
            {
                set[state_canto_val] = -tail;
                next_state.state_num = MapToStateNum();
                next_state.pre = 0;
                next_state.pre_dir = 0;
                next_state.next = head;
                next_state.next_dir = MoveDirection(false, i);
                state_queue[tail++] = next_state;
            }
            else if (state_queue[head].pre == 0 && set[state_canto_val] > 0)
            {
                state_queue[abs(set[state_canto_val])].next = head;
                state_queue[abs(set[state_canto_val])].next_dir = MoveDirection(false, i);
                return abs(set[state_canto_val]);
            }
            else if (state_queue[head].next == 0 && set[state_canto_val] == 0)
            {
                set[state_canto_val] = tail;
                next_state.state_num = MapToStateNum();
                next_state.pre = head;
                next_state.pre_dir = MoveDirection(true, i);
                next_state.next = 0;
                next_state.next_dir = 0;
                state_queue[tail++] = next_state;
            }
            else if (state_queue[head].next == 0 && set[state_canto_val] < 0)
            {
                state_queue[abs(set[state_canto_val])].pre = head;
                state_queue[abs(set[state_canto_val])].pre_dir = MoveDirection(true, i);
                return abs(set[state_canto_val]);
            }

            temp_swap = map[now_x + now_y * 3];
            map[now_x + now_y * 3] = map[next_x + next_y * 3];
            map[next_x + next_y * 3] = temp_swap;
        }
        head++;
    }
    return -1;
}

void PrintPath(int id)
{
    int pos = 0;
    int temp_id = id;

    while (state_queue[temp_id].pre != -1)
    {
        path[pos++] = state_queue[temp_id].pre_dir;
        temp_id = state_queue[temp_id].pre;
    }

    for (int i = pos - 1; i >= 0; --i)
        printf("%c", path[i]);

    temp_id = id;
    while (state_queue[temp_id].next != -1)
    {
        printf("%c", state_queue[temp_id].next_dir);
        temp_id = state_queue[temp_id].next;
    }

    printf("
"); } int main() { int ans = 0; char temp_value; for (int i = 0; i < 9; ++i) { cin >> temp_value; if (temp_value == 'x') map[i] = 9; else map[i] = temp_value - '0'; } memset(set, 0, sizeof(set)); ans = BFS(); if (ans == -1) printf("unsolvabel
"); else if (ans == -2) printf("
"); else PrintPath(ans); return 0; }