双向BFS
这题需要特判无法变换到得情况,我们发现每次变换8个数字的逆序数奇偶性都是不变的,所以找出给定的序列的逆序数可以特判不存在的情况。
康托展开:http://www.cnblogs.com/hxsyl/archive/2012/04/11/2443009.html
开个结构体node2存当前的string,并且存它的x出现在哪个位置,然后把string康托展开得到一个数p当作是这个string的编号,vis[p]就是当前这个是第几个字符串
开个结构体数组存第k字符串的前一个的编号是多少,然后再存下操作是什么。
之后是双向BFS,跟单BFS用的一样,从开头和终点一起开始BFS,直到两个BFS相遇,就是最短的路程了。这样可以缩短很长的时间,why?例如一个迷宫,我们假设没有边界,没有墙的空地,单BFS需要4^n时间,那双向BFS就是4^(n/2)*2,缩短了很多。
(A*算法并不懂,改天再学,这个就当熟悉一下康托展开和双向BFS了)
#include <iostream> #include <cstdio> #include <cctype> #include <cstdlib> #include <cmath> #include <algorithm> #include <cstring> #include <string> #include <vector> #include <queue> #include <map> #include <set> #include <sstream> #include <stack> using namespace std; #define MAX 1000000+5 #define MAXN 100000+5 typedef long long LL; const double pi=3.141592653589793; const int INF=0x3f3f3f3f; const int INFF=1e9; const double inf=1e18; const double eps=1e-10; const int mod=1000000007; int dir[4]={-3,3,-1,1}; char d1[10]={"udlr"}; char d2[10]={"durl"}; int hhash[9]={1,1,2,6,24,120,720,5040,40320}; int vis[MAX]; int vis2[MAX]; struct node{ int num; char d; }pre[MAX]; struct node2{ string c; int num; }e; string s="123456780"; int get_hash(string s){ int temp=0; int len=s.size(); for(int i=0;i<len-1;i++){ int k=0; for(int j=i+1;j<len;j++){ if(s[i]>s[j]) k++; } temp+=k*hhash[len-1-i]; } return temp; } void show(int x){ if(pre[x].num==-1) return ; show(pre[x].num); printf("%c",pre[x].d); } void bfs(){ queue<node2> q1; queue<node2> q2; node2 f,g; f.c=s; f.num=8; vis[get_hash(e.c)]=1; pre[1].num=-1; vis2[get_hash(f.c)]=2; pre[2].num=-1; int num=2; q1.push(e); q2.push(f); while(!q1.empty()&&!q2.empty()){ f=q1.front(); q1.pop(); int p=get_hash(f.c); if(vis2[p]){ show(vis[p]); int k=vis2[p]; while(pre[k].num!=-1){ printf("%c",pre[k].d); k=pre[k].num; } printf("\n"); return; } for(int i=0;i<4;i++){ if(i==0&&f.num<3)continue; if(i==1&&f.num>5)continue; if(i==2&&f.num%3==0)continue; if(i==3&&f.num%3==2)continue; int x=f.num+dir[i]; g=f; swap(g.c[f.num],g.c[x]); int q=get_hash(g.c); if(!vis[q]){ vis[q]=++num; g.num=x; pre[num].num=vis[p]; pre[num].d=d1[i]; q1.push(g); } } f=q2.front(); q2.pop(); p=get_hash(f.c); if(vis[p]){ show(vis[p]); int k=vis2[p]; while(pre[k].num!=-1){ printf("%c",pre[k].d); k=pre[k].num; } printf("\n"); return; } for(int i=0;i<4;i++){ if(i==0&&f.num<3)continue; if(i==1&&f.num>5)continue; if(i==2&&f.num%3==0)continue; if(i==3&&f.num%3==2)continue; int x=f.num+dir[i]; g=f; swap(g.c[f.num],g.c[x]); int q=get_hash(g.c); if(!vis2[q]){ vis2[q]=++num; g.num=x; pre[num].num=vis2[p]; pre[num].d=d2[i]; q2.push(g); } } } printf("unsolvable\n"); } int main(){ char a[30]; while(gets(a)){ int n=strlen(a); e.c=""; for(int i=0,j=0;i<n;i++){ if(a[i]!=' '){ if(a[i]=='x'){ e.num=j; e.c=e.c+'0'; } else e.c=e.c+a[i]; j++; } } memset(vis,0,sizeof(vis)); memset(vis2,0,sizeof(vis2)); int k=0; for(int i=0;i<9;i++){ if(e.c[i]=='0') continue; for(int j=0;j<i;j++){ if(e.c[j]=='0') continue; if(e.c[j]>e.c[i]) k++; } } if(k%2) printf("unsolvable\n"); else bfs(); } return 0; }