1. 程式人生 > >HDU 1043 Eight(反向BFS+打表+康托展開)

HDU 1043 Eight(反向BFS+打表+康托展開)

front int 二維 -i 轉換成 思路 離散化 strlen acm

題目鏈接:http://acm.hdu.edu.cn/showproblem.php?pid=1043

題目大意:傳統八數碼問題

解題思路:就是從“12345678x”這個終點狀態開始反向BFS,將各個狀態記錄下來,因為數字太大所以用康托展開將數字離散化。

代碼:

 1 #include<iostream>
 2 #include<algorithm>
 3 #include<cstdio>
 4 #include<cstring>
 5 #include<string>
 6 #include<queue>
 7
using namespace std; 8 typedef long long ll; 9 const int N=4e5+5; 10 11 int vis[N]; 12 string path[N]; 13 char map[15]; 14 char index[5]="udrl";//因為是逆向所以方向要反一下 15 int d[4][2]={{1,0},{-1,0},{0,-1},{0,1}}; 16 int fac[15]={1,1,2,6,24,120,720,5040,40320}; 17 18 struct node{ 19 char num[10]; 20 int
pos; 21 string path; 22 }pre,now; 23 24 //求康托展開值 25 int cantor(char s[]){ 26 int sum=0; 27 int n=strlen(s); 28 for(int i=0;i<n;i++){ 29 int cnt=0; 30 for(int j=i+1;j<n;j++){ 31 if(s[i]>s[j]) 32 cnt++; 33 } 34 sum+=cnt*fac[n-i-1
]; 35 } 36 return sum+1; 37 } 38 //從12345678x逆向BFS打表 39 void bfs(){ 40 queue<node>q; 41 now.pos=8; 42 for(int i=0;i<8;i++) 43 now.num[i]=i+1+0; 44 now.num[8]=0; 45 now.num[9]=\0; 46 q.push(now); 47 while(!q.empty()){ 48 pre=q.front(); 49 q.pop(); 50 int pos=pre.pos; 51 //轉換成二維坐標 52 int x=pos/3; 53 int y=pos%3; 54 for(int i=0;i<4;i++){ 55 int xx=x+d[i][0]; 56 int yy=y+d[i][1]; 57 if(xx<0||yy<0||xx>2||yy>2) 58 continue; 59 //轉換回一維坐標 60 int new_pos=xx*3+yy; 61 now=pre; 62 swap(now.num[pos],now.num[new_pos]); 63 int tmp=cantor(now.num); 64 if(!vis[tmp]){ 65 now.pos=new_pos; 66 //index[i]要加在前面,反的嘛 67 now.path=index[i]+now.path; 68 vis[tmp]=1; 69 //存儲路徑 70 path[tmp]=now.path; 71 q.push(now); 72 } 73 } 74 } 75 } 76 77 int main(){ 78 char c; 79 bfs(); 80 while(cin>>c){ 81 //x轉換成0便於康托展開 82 if(c==x) 83 map[0]=0; 84 else 85 map[0]=c; 86 for(int i=1;i<9;i++){ 87 cin>>map[i]; 88 if(map[i]==x) 89 map[i]=0; 90 } 91 int aim=cantor(map); 92 if(vis[aim]) 93 cout<<path[aim]<<endl; 94 else 95 cout<<"unsolvable"<<endl; 96 } 97 }

HDU 1043 Eight(反向BFS+打表+康托展開)