天天看點

BFS之四(雙向bfs和康托壓縮)

/*      
雙向BFS就是從起點 和 終點 同時開始搜尋。由起點搜尋(BSF1)得到的點标記為1,      
由終點搜尋(BFS2)得到的點标記為2。當某一時刻BFS1搜尋到了已經标記為2的點(或BFS2搜到      
了1号點),說明發生相遇,那麼答案就是由bfs1和bfs2分别求得的兩段路徑長度的和。      
簡單的分析:設每次的BFS,總的搜尋狀态數是r^L(r是搜尋的分支數,L是搜尋層數)。而采      
取雙向BFS算法,那麼,從前往後、從後往前,分别需要搜尋L/2層,合起來就是2*(r^(L/2))      
這要比一般的BFS快的多。      
可以看到,雙向BFS不過就是在while循環中套了兩個節點擴充子產品,一個是qu1,一個是qu2      
二者輪流執行、輪流擴充。qu1擴充一次,然後qu2擴充一次,直到二者中有點相遇為止。      
*/      
//poj 1077 Eight      
#include <iostream>            //雙向bfs和康托壓縮      
#include <deque>      
#include<string>      
#include<cmath>      
using namespace std;      
int visited[1000000];      
int fac[]={1,1,2,6,24,120,720,5040,40320,362880};    //9!表      
string path1[1000000],path2[1000000];      
int cantor(int arr[])      
{      
int temp,num=1;      
for(int i=0;i<9;++i)      
{      
temp=0;      
for(int j=i+1;j<9;++j)      
if(arr[j]<arr[i])      
temp++;      
num+=fac[8-i]*temp;      
}      
return num;      
}      
void to_arr(int list[],int num)      
{      
int i;      
for(i=0;i<9;++i)      
list[i]=0;      
i=8;      
while(num)      
{      
list[i--]=num%9;      
num/=9;      
}      
}      
int to_num(int list[])      
{      
int n=0;      
for(int i=0;i<9;++i)      
n=n*9+list[i];      
return n;      
}      
int move[4]={-3,3,1,-1};      
char pos[4]={'u','d','r','l'};      
struct node            //空間開銷是58276K      
{      
string state;      
int num;      
int sub;      
node(string str,int n,int dir,int s)      
{      
int arr[9];      
to_arr(arr,n);      
num=n;      
state=str;      
if(dir==0)      
sub=s;      
else      
{      
state.push_back(pos[dir-1]);      
swap(arr[s+move[dir-1]],arr[s]);      
num=to_num(arr);      
sub=s+move[dir-1];      
}      
}      
};      
deque<node> forword,backword;      
int main()      
{      
int arr[9]={1,2,3,4,5,6,7,8,0},loc;      
node bck("",to_num(arr),0,8);      
backword.push_back(bck);      
char ch;      
for(int i=0;i<9;++i)      
{      
cin>>ch;      
if(ch=='x')      
arr[i]=0,loc=i;      
else      
arr[i]=int(ch-48);      
}      
node forw("",to_num(arr),0,loc);      
forword.push_back(forw);      
while(!forword.empty())      
{      
node temp=forword.front();      
forword.pop_front();      
to_arr(arr,temp.num);      
int d=cantor(arr);      
if(visited[d]==2)      
{      
cout<<temp.state;      
for(int k=path2[d].size()-1;k>=0;--k)      
{      
ch=path2[d][k];      
if(ch=='u')      
cout<<'d';      
else if(ch=='d')      
cout<<'u';      
else if(ch=='r')      
cout<<'l';      
else      
cout<<'r';      
}      
cout<<endl;      
return 0;      
}      
else if(visited[d]==0)      
{      
visited[d]=1;      
path1[d]=temp.state;      
if(temp.sub>=3)      
{      
node puzzle(temp.state,temp.num,1,temp.sub);      
forword.push_back(puzzle);      
}      
if(temp.sub<6)      
{      
node puzzle(temp.state,temp.num,2,temp.sub);      
forword.push_back(puzzle);      
}      
if(temp.sub%3!=2)      
{      
node puzzle(temp.state,temp.num,3,temp.sub);      
forword.push_back(puzzle);      
}      
if(temp.sub%3!=0)      
{      
node puzzle(temp.state,temp.num,4,temp.sub);      
forword.push_back(puzzle);      
}      
}      
if(!backword.empty())      
{      
node temp=backword.front();      
backword.pop_front();      
to_arr(arr,temp.num);      
int d=cantor(arr);      
if(visited[d]==1)      
{      
cout<<path1[d];      
for(int k=temp.state.size()-1;k>=0;--k)      
{      
ch=temp.state[k];      
if(ch=='u')      
cout<<'d';      
else if(ch=='d')      
cout<<'u';      
else if(ch=='r')      
cout<<'l';      
else      
cout<<'r';      
}      
cout<<endl;      
return 0;      
}      
else if(visited[d]==0)      
{      
visited[d]=2;      
path2[d]=temp.state;      
if(temp.sub>=3)        //u d r l      
{      
node puzzle(temp.state,temp.num,1,temp.sub);      
backword.push_back(puzzle);      
}      
if(temp.sub<6)      
{      
node puzzle(temp.state,temp.num,2,temp.sub);      
backword.push_back(puzzle);      
}      
if(temp.sub%3!=2)      
{      
node puzzle(temp.state,temp.num,3,temp.sub);      
backword.push_back(puzzle);      
}      
if(temp.sub%3!=0)      
{      
node puzzle(temp.state,temp.num,4,temp.sub);      
backword.push_back(puzzle);      
}      
}      
}      
}      
cout<<"unsolvable\n";      
return 0;      
}