A*(A - Star) - Eight - HDU - 1043

A*(A - Star) - Eight - HDU - 1043

題意:

3×31給定一個3×3的方陣,包含數字1~8x()x使98,以及字符'x'(表示空位),\\每次操作通過上下左右移動數字到'x'所在的空位上,使得最終呈現一個有序的9宮格。

使9要通過最少的操作次數使得9宮格復位,輸出一個最少操作方案。

使9unsolvable.若不能使9宮格有序,則輸出''unsolvable''.

uxdxrxlx'u'表示將'x'向上移動,'d'表示將'x'向下移動,'r'表示將'x'向右移動,'l'表示將'x'向左移動。

Sample Input

2  3  4  1  5  x  7  6  8

Sample Output

ullddrurdllurdruldr

Time limit: 5000 ms
Memory limit: 32768 kB
Special judge : Yes


分析:

與——POJ 1077 - 八數碼題意一致,僅僅是需要輸出具體操作方案。

使有一個重要的性質:若序列中的逆序對數量是奇數,則無法使得九宮格有序。

f(st)st設啓發函數f(st)表示從狀態st到終點狀態需要的最少操作次數。

d[st]std[st]表示從起始狀態到當前狀態st已經進行的操作次數。

d[st]+f(st)end對於每次操作,我們優先選擇d[st]+f(st)更小的狀態進行操作,\\當終點狀態end第一次出隊時,就得到最少操作的一種方案。

具體落實:

pre①、因爲要求出具體方案,定義哈希表pre,把每一種狀態與前驅狀態和從前驅狀態轉移而來的操作對應起來。

d②、距離數組d,存儲從起始狀態到當前狀態已經進行的操作次數。

heapd[st]+f(st)③、小根堆heap,以d[st]+f(st)爲第一關鍵字,堆中元素是一個估計距離和對應狀態的一個二元組。

④、先將初始狀態入堆,每次從堆中取出堆頂元素進行擴展,\\\qquad若某個狀態未搜索過,或者重複搜索到當前狀態時距離更優,就把該狀態入堆。

退pre⑤、當第一次從堆頂得到終點狀態,提前退出循環,根據pre表倒推具體操作。

f⑥、f函數的具體實現:對當前狀態的每一個數字,計算該數字當前位置與其在終點狀態中的位置的曼哈頓距離。

注意:本題是多組測試數組!!!

代碼:

#include<iostream>
#include<cstring>
#include<vector>
#include<algorithm>
#include<queue>
#include<unordered_map>

#define P pair<int,string>

using namespace std;

int f(string start)
{
    int res=0;
    for(int i=0;i<9;i++)
        if(start[i]!='x')
        {
            int t=start[i]-'1';
            res+=abs(i/3-t/3)+abs(i%3-t%3);
        }
    return res;
}

string bfs(string start)
{
    int dir[4][2]={{-1,0},{1,0},{0,-1},{0,1}};
    char op[4]={'u','d','l','r'};
    string end="12345678x";
    
    unordered_map<string,pair<string,char>> pre;
    unordered_map<string,int> d;
    priority_queue<P,vector<P>,greater<P>> heap;
    
    d[start]=0;
    heap.push(make_pair(f(start),start));

    while(heap.size())
    {
        P t=heap.top();
        heap.pop();
        string state=t.second;
        int step=d[state];
        
        if(state==end) break;
        
        int x,y;
        for(int i=0;i<9;i++)
            if(state[i]=='x')
            {
                x=i/3,y=i%3;
                break;
            }
            
        string source=state;
        for(int i=0;i<4;i++)
        {
            int a=x+dir[i][0],b=y+dir[i][1];
            if(a>=0&&a<3&&b>=0&&b<3)
            {
                swap(state[x*3+y],state[a*3+b]);
                if(!d.count(state)||d[state]>step+1)
                {
                    d[state]=step+1;
                    heap.push(make_pair(d[state]+f(state),state));
                    pre[state]=make_pair(source,op[i]);
                }
                swap(state[x*3+y],state[a*3+b]);
            }
        }
    }
    
    string res;
    while(start!=end)
    {
        res+=pre[end].second;
        end=pre[end].first;
    }
    reverse(res.begin(),res.end());
    return res;
}

int main()
{
    string c;
    while(cin>>c)
    {
    	string seq,start;
        start+=c;
        if(c!="x") seq+=c;     //用於計算逆序對數量
    	for(int i=0;i<8;i++)
    	{
    		cin>>c;
    		start+=c;
        	if(c!="x") seq+=c;
    	}
    	
	    int cnt=0;
	    for(int i=0;i<7;i++)
	        for(int j=i+1;j<8;j++)
	            if(seq[i]>seq[j])
	                cnt++;
	            
	    if(cnt%2) cout<<"unsolvable"<<endl;
	    else cout<<bfs(start)<<endl;
    }
    
    return 0;
} 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章