B - Eight II HDU - 3567(bfs+預處理)

B - Eight II HDU - 3567

思路

  1. 這一題由於是多組輸入,如果我們對每一組輸入都進行一遍 bfs 這樣肯定會T,
  2. 那麼這一題的,奇妙思路就是預處理所有可能產生的終點狀態,進行bfs逆向bfs
  3. 我們假設所以的逆向狀態爲:

“X12345678”,
“1X2345678”,
“12X345678”,
“123X45678”,
“1234X5678”,
“12345X678”,
“123456X78”,
“1234567X8”,
“12345678X”,

  1. 對於題目的中給我兩個 起始、終點狀態我們可以做對應的數字替換,過程爲
    1. 設起始狀態a:564178X23,
    2. 設終點狀態b:7568X4123
    3. 我們把終點狀態b 轉化爲上面9個狀態中的一個(取決於X的位置):得到新的終點狀態b’『1 2 3 4 X 5 6 7 8』—在這個轉話過程重 7->1、5->2、6->3、8->3、X->X、4->5、1->6、2->7、3->8.
    4. 那麼我們對起始狀態a也相同的數字替換,就得到了新的起始狀態a’ =『2 3 5 6 1 3 X 7 8』
    5. 接下來是預處理9個終點狀態對它們分別跑一遍bfs,這樣每一個終點狀態會通過一層一層的搜索產生許多的 起點狀態,
  2. 有了上面的預處理操作,對於每一組 始末狀態 a、b我們對應轉化爲a’、b’,通過a’、b’ 在結合 預處理已經預處理時記錄的路徑,就能快速的得到ans了,,--------具體詳細的還是看代碼

代碼

#include<iostream>  
#include<algorithm>
#include<cstring>
#include<queue>
#include<map>
#include<string>
#include<cstdio>
#include<cmath>
#include<stack>
void fre() { freopen("A.txt", "r", stdin); freopen("Ans.txt","w",stdout); } void Fre() { freopen("A.txt", "r", stdin);}
#define ios ios::sync_with_stdio(false)
#define Pi acos(-1)
#define pb push_back
#define fi first
#define se second
#define ll long long
#define ull unsigned long long 
#define db double
#define Pir pair<int, int>
#define PIR pair<Pir, Pir>
#define m_p make_pair
#define INF 0x3f3f3f3f
#define mod (ll)(1e9 + 7)
#define for_(i, s, e) for(int i = (s); i <= (e); i ++)
#define rep_(i, e, s) for(int i = (e); i >= (s); i --)
#define sd(a) scanf("%d", &a)
#define sc(a) scanf("%c", &a)
using namespace std;



struct Poi
{
    char a[4][4];
    Poi() {};
    Poi(char s[]) 
    {
        for_(i, 0, 2)
            for_(j, 0, 2)
            a[i][j] = s[i * 3 + j];
    }
};

char s[20], t[20];
int mk[9][500001];                  //標記搜索的中的狀態
vector<pair<int, char> > pa;        //記錄路徑 <父節點索引,當前操作的符合>
int mov[4][2] = { 1, 0, 0, -1, 0, 1, -1, 0 };
int mul[9];                         //提前預處理階乘
char statu[9][20] = {               //提前寫出來我們要預轉換成的9的個狀態,要注意X的位置
    "X12345678",
    "1X2345678",
    "12X345678",
    "123X45678",
    "1234X5678",
    "12345X678",
    "123456X78",
    "1234567X8",
    "12345678X",
};

char dir[5] = "dlru";       //因爲是字典最小,所以搜索的 方向的先後順序要注意
ll get_hash(Poi p)
{
    int res = 0;
    char te[20];
    for_(i, 0, 2)
        for_(j, 0, 2)
        {
            int cnt = 0;
            te[i * 3  + j] = p.a[i][j];
            for_(k, 0, i * 3 + j - 1)
                if(te[k] > te[i * 3 + j])
                    cnt ++;
            res += cnt * mul[i * 3 + j];
        }
    return res;
}

void bfs(int k)                 //以終點狀態statu[k]數組,來逆向搜索的得出的 從終點狀態能演變出的所有的其它狀態(這的狀態指的是的有 1~8、和X組成的序列)狀態 
{
    Poi s(statu[k]);
    queue<pair<Poi, pair<int, int> > > q;          //<狀態,<父節點索引,X的位置>
    q.push(m_p(s, m_p(-1, k)));
    mk[k][get_hash(s)] = -1;    //對起點做一下標記

    while(! q.empty())
    {
        pair<Poi, pair<int, int> > t = q.front(); q.pop();
        int x = t.se.se / 3, y = t.se.se % 3;
        for_(i, 0, 3)
        {
            int xx = x + mov[i][0];
            int yy = y + mov[i][1];
            if(xx < 0 || yy < 0 || xx >= 3 || yy >= 3) continue;
            swap(t.fi.a[x][y], t.fi.a[xx][yy]);
            if(! mk[k][get_hash(t.fi)]) 
            {
                mk[k][get_hash(t.fi)] = pa.size();      //這裏我們千萬要注意:mk 裏面的存儲的是 pa的尺寸,有pa容器的尺寸是不斷的變大的,所以我們可以把它作爲一個唯一的 標識下標(這個標識 在後面作爲 路徑記錄時的下標來用)
                q.push(m_p(t.first, m_p(pa.size(), xx * 3 + yy)));
                pa.pb(m_p(t.se.fi, dir[i]));            //pa的容器尺寸++
            }
            swap(t.fi.a[x][y], t.fi.a[xx][yy]);         //還原回來原來的改變
        }
    }
}

void sol()
{
    int num[300], p = 0;
    for(int i = 0, j = 0; i < 9; i ++)                  //我們將b數組轉化成 某個標準狀態數組 statu(預處理成哪一個取決於X的位置)
        if(s[i] == 'X') p = i;                          //記錄p記錄X的位置
        else num[s[i]] = ++ j;                          

    for_(i, 0, 8) if(t[i] != 'X') t[i] = num[t[i]] + '0';   //相應的數字進行對應轉化
    int hs = mk[p][get_hash(t)];                        //我們考慮p的意思 和 mk 存儲的是什麼?
    vector<char> ans;               //記錄ans
    while(hs != -1)
    {
        ans.pb(pa[hs].se);
        hs = pa[hs].fi;
    }
    printf("%lu\n", ans.size());
    rep_(i, ans.size() - 1, 0)
        printf("%c", ans[i]);
    printf("\n");
}



int main()
{
    /* fre(); */
    mul[0] = 1;
    for_(i, 1, 9) mul[i] = mul[i - 1] * i;      //預處理階乘
    for_(i, 0, 8) bfs(i);                       //預處理 每一個可能的終點狀態statu[i],到其它狀態的轉換
    int T, Case = 1;
    sd(T);
    while(T --)
    {
        scanf("%s %s", s, t);        
        printf("Case %d: ", Case ++);
        sol();
    }

    return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章