hdu3567 雙向BFS

太感人了,錯了一天看了一天,終於AC了!
彷彿人生度過了幾個輪迴嗚嗚嗚

這題,看題解都是雙向BFS,因爲雙向比單向快了好多
雙向,說白就是一鍵雙開,讓你在開前面的時候順便開後面,用兩個隊列也行,一個隊列更好寫,因爲你得開完兩個隊列前面一層再開後面一層,你只要用一個
flag標記一下前後即可
1.
然後正向與反向有什麼區別呢,正向遇到反向的最小,纔是最小,而反向的最小遇到正向,此時不一定是最小
例如題目的順序是 dlru
那麼你兩邊都是從dlru那麼走,
假設你的後面走了dl 忽然發現前面有一個u剛好可以,那你就直接 udl輸出
而實際上 後面來的 ul 哭了 ,它遇到了 d 是 dul 爲啥子它比較小反而不行,那怎麼辦呢,只能後面的時候只儲存就好啦,反正正向遲早可以找到自己的!省的鬧麻煩勒
還有一件事,後面走的,,如果 你先來一個 ud ,後面 來了一個 du ,你和它走到了相同的位置, 不就很尷尬? 所以你必須要比較一下誰大誰佔坑!順便別忘了把 du 也隊列放進去跑哦
2.
接下來比較不會考慮的是存儲路經
用string 感覺太大,所以採用4進制的long long 來存儲,但又有一個問題,如果它一直走d,不就一直0?所以爲了防止漏0,俺先給它賦值爲1
正向直接就 (4進製表示) 1->10->103->1032
反向爲了防止比較大小的時候出錯,所以把它採用正向儲存,用了一個path數組來儲存4進制進位,其就爲 1 -> 13 -> 123 -> 1023 這個樣子
在方向的時候需注意:反向走dlru的時候 下則要走上!左則要走右!爲了走dlru,所以寫了 3-i
3.
map<string, long long> 會炸TLE
map<long long , long long> 不會
4.
第一步要注意不用亂把不該放的放進去 不然你可能會 MLE
代碼如下

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <queue>
#include <string>
#include <cstring>
#include <map>
using namespace std;
string be,en; //儲存開始序列和結束序列 
long long s1,s2;//存正向和反向要輸出的 
char ss[1000];//用於輸出 
int dis[4][2]= { {1,0},{0,-1},{0,1},{-1,0} };  //dlru正  反ulrd 
char c[]="dlru";
long long path[100];//存儲4進制 
long long pu(string s)//將序列化爲數字存儲狀態 
{
    long long sum =  0;
    int n = s.size();
    for (int i = 0; i < n; i++)
    {
        sum = sum*10+((s[i] == 'X')?0:s[i]-'0');
    }
    return sum;
}
struct stu{
    long long wei;//儲存已經走的路勁    
    int flag; 		//正反 
    string S;		//目前隊列 
    int bu;			//已走步數 
};
map <long long , long long> C,C1; // 狀態存儲 順便路勁儲存 
void BFS()
{
    C.clear(); C1.clear(); //初始化 
    if(be == en) return ; //一樣的情況 
        stu Be,Nex,En; 
            long long s = pu(be);     	C[s] = 1;  
                Be.wei = 1; Be.flag = 0; Be.S = be;
                        s = pu(en);     C1[s] = 1; 
                En.wei = 1; En.flag = 1; En.S = en;
                Be.bu = 0; En.bu = 0;
    queue <stu> q;
    q.push(Be); q.push(En); 
    while( !q.empty() ){
        Be = q.front();     q.pop();
        int W  = 0;
        for (int i = 0; i < 9; i++) 
			if(Be.S[i] == 'X')  {  //找到0 的位置 
            		W = i; break;
        	}
        int x = W/3,  y = W%3;
        for (int i = 0; i < 4; i++){
            Nex = Be; 		Nex.bu++; // 先加一步 
            int newx,newy; 		
                if(!Be.flag)		//爲了走dlru 
                {
                    newx = x + dis[i][0],newy = y + dis[i][1];
                }
                else{
                    newx = x + dis[(3-i)][0],newy = y + dis[(3-i)][1];  //3-i 
                }
            int newW = newx*3 + newy; 	
            if(newx >= 0 && newx < 3 &&  newy >= 0 && newy < 3 ){
                swap(Nex.S[W],Nex.S[newW]);
                long long s  = pu(Nex.S);
                
                if(!Be.flag && !C.count(s)){
                    Nex.wei = Nex.wei*4 + i;  //推的 
                        C[s] = Nex.wei;	
                    if(C1.count(s)){
                        s1 = C[s]; s2 = C1[s];
                        return;
                    }    
                        q.push(Nex);
                }
                else if( Be.flag  ){
                        Nex.wei = Nex.wei-path[Be.bu]*1 + i*path[Be.bu] + 1*path[Nex.bu];//推的 
                        if(!C1.count( s )){
                        	 C1[ s ]  = Nex.wei; q.push(Nex);
						}
						else{
							if( C1[s] > Nex.wei ) {
								C1[s] = Nex.wei;
								q.push(Nex);
							}
						}                      
                        /*if(C.count((Nex.S))){
                            s1 = C[Nex.S]; s2 = C1[Nex.S];
                            return;
                        }*///沒有權力,只能等人拯救                            
                } 
            }    
        }
    }   
}
int main()
{
    int n; int k = 1;
    for (int i = 0; i < 30;i++)
    {
        path[i] = k;
        k*=4;
    }//將四進制階數求出 
     scanf("%d",&n);
     for (int i = 0; i < n; i++)
     {
         memset(ss,0,sizeof(ss)); 
		 int mm = 0;
         cin >> be >> en;  s1 = 1;  s2 = 1;
         BFS();
         //十進制轉四進制 
         while(s1!=1 && s1>0){
             int k = s1%4;
             ss[mm++] = c[k];
             s1/=4; 
        }
         for (int j = 0; j < mm/2; j++){
             char t = ss[j]; ss[j] = ss[mm-j-1];
             ss[mm-j-1] = t;
         }
         int zz = mm;
         while(s2!=1 && s2>0){
             int k = s2%4;
             ss[mm++] = c[k];
            s2/=4; 
         }
         printf("Case %d: %d\n",i+1,mm);
         for (int i = 0; i < zz; i++){
             printf("%c",ss[i]);
         }
         for (int i = mm-1; i >= zz; i--){
             printf("%c",ss[i]);
         }
         printf("\n");
    } 
 } 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章