八数码第五境界——双向BFS+康托展开判重+回溯记录路径
2017-12-13 23:06
351 查看
(请先看前4大境界)
这里较上一境界,就是把反向的BFS,弄成了双向的BFS。先不说算法的优劣,就光这个双向的BFS,就是指的记录和学习的。
很简单,在结合之前所学的基础上,把单向扩展成双向即可。
结构体
struct node
{
char str[10];
int mark,num;
int index,hashnum;
};
这里的结构体,增加了一个mark,用来判断他是从终点开始bfs的(mark=0)还是从我们所要求的起点开始bfs的(mark=1)。
回溯路径结构体数组,就需要多开一个
struct res
{
int fa,now;
}res1
,res2
;
访问与否,也需要多开一个
int vis1
,vis2
;
先让终点状态入队列
g.mark=0;g.num=0;g.index=8;
vis1[KT(g.str)]=0;
q.push(g);
再让起点状态入队列
for(int i=0;i<9;i++)
g.str[i]=ss[i];
g.mark=1;g.num=0;g.index=temp;
vis2[KT(g.str)]=0;
q.push(g);
所以这里我们得知了,我们虽然是bfs,但是仍旧共享一个队列,我们一开始,也是将两个开始状态都入队。
如果找到,应该进行的判断
if(g.mark==0&&vis2[t]!=-1)
{
ans1=g.num;
ans2=vis2[t];
return true;
}
if(g.mark==1&&vis1[t]!=-1)
{
ans2=g.num;
ans1=vis1[t];
return true;
}
g.mark==0指代的是从终点开始bfs的,vis2[t]!=-1指代的是这个状态,从起点开始的bfs他走到过。(所以这里用的vis2)
bfs流程
h=g;
if((h.index+1)%3!=0)
{
c=h.str[h.index];h.str[h.index]=h.str[h.index+1];h.str[h.index+1]=c;
h.index++;
if(!h.mark){res1[cnt1].now=4;res1[cnt1].fa=h.num;h.num=cnt1;cnt1++;}
else {res2[cnt2].now=4;res2[cnt2].fa=h.num;h.num=cnt2;cnt2++;}
int t=KT(h.str);
if(vis1[t]==-1&&!h.mark)
{
vis1[t]=h.num;
q.push(h);
sum1++;
}
else if(vis2[t]==-1&&h.mark)
{
vis2[t]=h.num;
q.push(h);
sum2++;
}
}
首先第一个if,意思就是不为第三列,那就是前面两列,所以自然肯定可以右移。
c=h.str[h.index];h.str[h.index]=h.str[h.index+1];h.str[h.index+1]=c; 这个就是右移操作
h.index++; 指代h状态中x所在的位置
接下来的那个if,!h.mark,那意思就是为0的情况,那就是从终点开始的bfs。
if里面的内容就是用来回溯路径的。
else就是代表从起点开始的bfs。
这个时候h较g已经发生了改变,再通过康托展开取得值。
接下来的if。如果这个状态再vis1中未曾出现过且现在是起点开始的bfs,那就把这个状态置为已访问,再把这个新的状态入队列。
最后的sum1++就耐人寻味了。
我们先找到sum所在的地方
声明处
sum1=sum2=1;
while(!q.empty())
{
g=q.front();q.pop();
int t = KT(g.str);
if(g.mark==0)sum1--;
else sum2--;
然后在每次入队列的的时候都会减1。所以这个num1就指代了你当前队列中,属于你终点开始的bfs在队列中还剩下几个元素。
最后的终止条件
if(sum1==0||sum2==0)
return false;
如果其中一个的元素出光了,那就代表返回false,退出了。为什么其中一个元素出光了就代表没机会了呢?难道不能之后从另一个点出发的bfs又走回到你这个路径上来了呢?其实我想说,仅仅这样还限定的不严格。不过我们就先谈谈这个。我们先假设,其中一个bfs所有情况遍历了,另一个bfs在随后走到了这条路上来。那么我想问,这是否意味着另一个bfs总有办法走到之前的bfs的路上来,也就证明他们是相通的。但是第一个bfs走光了,那肯定也代表他把能走相通的路都走过了!所以这是矛盾的。具体什么时候才是真正的没机会了呢?不必深究了。
全部代码
#define N 512345
char ss[10];
struct node
{
char str[10];
int mark,num;
int index,hashnum;
};
struct res
{
int fa,now;
}res1
,res2
;
int vis1
,vis2
;
int fac[] = {1,1,2,6,24,120,720,5040,40320};
int over,ans1,ans2,sum1,sum2,cnt1,cnt2;
int hehe
;
int KT(char ss[])
{
int i, j, t, sum;
int s[10];
for(i=0;i<9;i++)
{
if(ss[i]=='x')
s[i]=0;
else
s[i]=ss[i]-'0';
}
sum = 0;
for (i=0; i<9; i++)
{
t = 0;
for (j=i+1; j<9; j++)
if (s[j] < s[i])
t++;
sum += t*fac[9-i-1];
}
return sum+1;
}
bool bfs(char ss[], int temp)
{
char c;
queue<node> q;
while(!q.empty())q.pop();
node g,h;
for(int i=0;i<8;i++)
g.str[i]=i+1+'0';
g.str[8]='x';g.str[9]='\0';
g.mark=0;g.num=0;g.index=8;
vis1[KT(g.str)]=0;
q.push(g);
for(int i=0;i<9;i++)
g.str[i]=ss[i];
g.mark=1;g.num=0;g.index=temp;
vis2[KT(g.str)]=0;
q.push(g);
sum1=sum2=1;
cnt1=cnt2=1;
while(!q.empty())
{
g=q.front();q.pop();
int t = KT(g.str);
if(g.mark==0)sum1--;
else sum2--;
if(g.mark==0&&vis2[t]!=-1)
{
ans1=g.num;
ans2=vis2[t];
return true;
}
if(g.mark==1&&vis1[t]!=-1)
{
ans2=g.num;
ans1=vis1[t];
return true;
}
h=g;
if((h.index+1)%3!=0)
{
c=h.str[h.index];h.str[h.index]=h.str[h.index+1];h.str[h.index+1]=c;
h.index++;
if(!h.mark){res1[cnt1].now=4;res1[cnt1].fa=h.num;h.num=cnt1;cnt1++;}
else {res2[cnt2].now=4;res2[cnt2].fa=h.num;h.num=cnt2;cnt2++;}
int t=KT(h.str);
if(vis1[t]==-1&&!h.mark)
{
vis1[t]=h.num;
q.push(h);
sum1++;
}
else if(vis2[t]==-1&&h.mark)
{
vis2[t]=h.num;
q.push(h);
sum2++;
}
}
h=g;
if(h.index%3!=0)
{
c=h.str[h.index];h.str[h.index]=h.str[h.index-1];h.str[h.index-1]=c;
h.index--;
if(!h.mark){res1[cnt1].now=3;res1[cnt1].fa=h.num;h.num=cnt1;cnt1++;}
else {res2[cnt2].now=3;res2[cnt2].fa=h.num;h.num=cnt2;cnt2++;}
int t=KT(h.str);
if(vis1[t]==-1&&!h.mark)
{
vis1[t]=h.num;
q.push(h);
sum1++;
}
else if(vis2[t]==-1&&h.mark)
{
vis2[t]=h.num;
q.push(h);
sum2++;
}
}
h=g;
if(h.index<6)
{
c=h.str[h.index];h.str[h.index]=h.str[h.index+3];h.str[h.index+3]=c;
h.index+=3;
if(!h.mark){res1[cnt1].now=2;res1[cnt1].fa=h.num;h.num=cnt1;cnt1++;}
else {res2[cnt2].now=2;res2[cnt2].fa=h.num;h.num=cnt2;cnt2++;}
int t=KT(h.str);
if(vis1[t]==-1&&!h.mark)
{
vis1[t]=h.num;
q.push(h);
sum1++;
}
else if(vis2[t]==-1&&h.mark)
{
vis2[t]=h.num;
q.push(h);
sum2++;
}
}
h=g;
if(h.index>2)
{
c=h.str[h.index];h.str[h.index]=h.str[h.index-3];h.str[h.index-3]=c;
h.index-=3;
if(!h.mark){res1[cnt1].now=1;res1[cnt1].fa=h.num;h.num=cnt1;cnt1++;}
else {res2[cnt2].now=1;res2[cnt2].fa=h.num;h.num=cnt2;cnt2++;}
int t=KT(h.str);
if(vis1[t]==-1&&!h.mark)
{
vis1[t]=h.num;
q.push(h);
sum1++;
}
else if(vis2[t]==-1&&h.mark)
{
vis2[t]=h.num;
q.push(h);
sum2++;
}
}
if(sum1==0||sum2==0)
return false;
}
return false;
}
int main()
{
int i,j,k,kk,t,x,y,z;
while(scanf("%s",ss)!=EOF)
{
if(ss[0]=='x')x=0;
for(i=1;i<9;i++)
{
scanf("%s",ss+i);
if(ss[i]=='x') x=i;
}
ans1=ans2=-1;
memset(vis1,-1,sizeof(vis1));
memset(vis2,-1,sizeof(vis2));
res1[0].now=res2[0].now=-1;
if(bfs(ss,x))
{
x=0;
if(res2[ans2].now==-1&&res1[ans1].now==-1)
{
printf("lr\n");
continue;
}
while(res2[ans2].now!=-1)
{
hehe[x++]=res2[ans2].now;
ans2=res2[ans2].fa;
}
for(i=x-1;i>=0;i--)
{
if(hehe[i]==1)printf("u");
if(hehe[i]==2)printf("d");
if(hehe[i]==3)printf("l");
if(hehe[i]==4)printf("r");
}
while(res1[ans1].now!=-1)
{
if(res1[ans1].now==1)printf("d");
if(res1[ans1].now==2)printf("u");
if(res1[ans1].now==3)printf("r");
if(res1[ans1].now==4)printf("l");
ans1=res1[ans1].fa;
}
}
else
printf("unsolvable");
printf("\n");
}
return 0;
}
这里较上一境界,就是把反向的BFS,弄成了双向的BFS。先不说算法的优劣,就光这个双向的BFS,就是指的记录和学习的。
很简单,在结合之前所学的基础上,把单向扩展成双向即可。
结构体
struct node
{
char str[10];
int mark,num;
int index,hashnum;
};
这里的结构体,增加了一个mark,用来判断他是从终点开始bfs的(mark=0)还是从我们所要求的起点开始bfs的(mark=1)。
回溯路径结构体数组,就需要多开一个
struct res
{
int fa,now;
}res1
,res2
;
访问与否,也需要多开一个
int vis1
,vis2
;
先让终点状态入队列
g.mark=0;g.num=0;g.index=8;
vis1[KT(g.str)]=0;
q.push(g);
再让起点状态入队列
for(int i=0;i<9;i++)
g.str[i]=ss[i];
g.mark=1;g.num=0;g.index=temp;
vis2[KT(g.str)]=0;
q.push(g);
所以这里我们得知了,我们虽然是bfs,但是仍旧共享一个队列,我们一开始,也是将两个开始状态都入队。
如果找到,应该进行的判断
if(g.mark==0&&vis2[t]!=-1)
{
ans1=g.num;
ans2=vis2[t];
return true;
}
if(g.mark==1&&vis1[t]!=-1)
{
ans2=g.num;
ans1=vis1[t];
return true;
}
g.mark==0指代的是从终点开始bfs的,vis2[t]!=-1指代的是这个状态,从起点开始的bfs他走到过。(所以这里用的vis2)
bfs流程
h=g;
if((h.index+1)%3!=0)
{
c=h.str[h.index];h.str[h.index]=h.str[h.index+1];h.str[h.index+1]=c;
h.index++;
if(!h.mark){res1[cnt1].now=4;res1[cnt1].fa=h.num;h.num=cnt1;cnt1++;}
else {res2[cnt2].now=4;res2[cnt2].fa=h.num;h.num=cnt2;cnt2++;}
int t=KT(h.str);
if(vis1[t]==-1&&!h.mark)
{
vis1[t]=h.num;
q.push(h);
sum1++;
}
else if(vis2[t]==-1&&h.mark)
{
vis2[t]=h.num;
q.push(h);
sum2++;
}
}
首先第一个if,意思就是不为第三列,那就是前面两列,所以自然肯定可以右移。
c=h.str[h.index];h.str[h.index]=h.str[h.index+1];h.str[h.index+1]=c; 这个就是右移操作
h.index++; 指代h状态中x所在的位置
接下来的那个if,!h.mark,那意思就是为0的情况,那就是从终点开始的bfs。
if里面的内容就是用来回溯路径的。
else就是代表从起点开始的bfs。
这个时候h较g已经发生了改变,再通过康托展开取得值。
接下来的if。如果这个状态再vis1中未曾出现过且现在是起点开始的bfs,那就把这个状态置为已访问,再把这个新的状态入队列。
最后的sum1++就耐人寻味了。
我们先找到sum所在的地方
声明处
sum1=sum2=1;
while(!q.empty())
{
g=q.front();q.pop();
int t = KT(g.str);
if(g.mark==0)sum1--;
else sum2--;
然后在每次入队列的的时候都会减1。所以这个num1就指代了你当前队列中,属于你终点开始的bfs在队列中还剩下几个元素。
最后的终止条件
if(sum1==0||sum2==0)
return false;
如果其中一个的元素出光了,那就代表返回false,退出了。为什么其中一个元素出光了就代表没机会了呢?难道不能之后从另一个点出发的bfs又走回到你这个路径上来了呢?其实我想说,仅仅这样还限定的不严格。不过我们就先谈谈这个。我们先假设,其中一个bfs所有情况遍历了,另一个bfs在随后走到了这条路上来。那么我想问,这是否意味着另一个bfs总有办法走到之前的bfs的路上来,也就证明他们是相通的。但是第一个bfs走光了,那肯定也代表他把能走相通的路都走过了!所以这是矛盾的。具体什么时候才是真正的没机会了呢?不必深究了。
全部代码
#define N 512345
char ss[10];
struct node
{
char str[10];
int mark,num;
int index,hashnum;
};
struct res
{
int fa,now;
}res1
,res2
;
int vis1
,vis2
;
int fac[] = {1,1,2,6,24,120,720,5040,40320};
int over,ans1,ans2,sum1,sum2,cnt1,cnt2;
int hehe
;
int KT(char ss[])
{
int i, j, t, sum;
int s[10];
for(i=0;i<9;i++)
{
if(ss[i]=='x')
s[i]=0;
else
s[i]=ss[i]-'0';
}
sum = 0;
for (i=0; i<9; i++)
{
t = 0;
for (j=i+1; j<9; j++)
if (s[j] < s[i])
t++;
sum += t*fac[9-i-1];
}
return sum+1;
}
bool bfs(char ss[], int temp)
{
char c;
queue<node> q;
while(!q.empty())q.pop();
node g,h;
for(int i=0;i<8;i++)
g.str[i]=i+1+'0';
g.str[8]='x';g.str[9]='\0';
g.mark=0;g.num=0;g.index=8;
vis1[KT(g.str)]=0;
q.push(g);
for(int i=0;i<9;i++)
g.str[i]=ss[i];
g.mark=1;g.num=0;g.index=temp;
vis2[KT(g.str)]=0;
q.push(g);
sum1=sum2=1;
cnt1=cnt2=1;
while(!q.empty())
{
g=q.front();q.pop();
int t = KT(g.str);
if(g.mark==0)sum1--;
else sum2--;
if(g.mark==0&&vis2[t]!=-1)
{
ans1=g.num;
ans2=vis2[t];
return true;
}
if(g.mark==1&&vis1[t]!=-1)
{
ans2=g.num;
ans1=vis1[t];
return true;
}
h=g;
if((h.index+1)%3!=0)
{
c=h.str[h.index];h.str[h.index]=h.str[h.index+1];h.str[h.index+1]=c;
h.index++;
if(!h.mark){res1[cnt1].now=4;res1[cnt1].fa=h.num;h.num=cnt1;cnt1++;}
else {res2[cnt2].now=4;res2[cnt2].fa=h.num;h.num=cnt2;cnt2++;}
int t=KT(h.str);
if(vis1[t]==-1&&!h.mark)
{
vis1[t]=h.num;
q.push(h);
sum1++;
}
else if(vis2[t]==-1&&h.mark)
{
vis2[t]=h.num;
q.push(h);
sum2++;
}
}
h=g;
if(h.index%3!=0)
{
c=h.str[h.index];h.str[h.index]=h.str[h.index-1];h.str[h.index-1]=c;
h.index--;
if(!h.mark){res1[cnt1].now=3;res1[cnt1].fa=h.num;h.num=cnt1;cnt1++;}
else {res2[cnt2].now=3;res2[cnt2].fa=h.num;h.num=cnt2;cnt2++;}
int t=KT(h.str);
if(vis1[t]==-1&&!h.mark)
{
vis1[t]=h.num;
q.push(h);
sum1++;
}
else if(vis2[t]==-1&&h.mark)
{
vis2[t]=h.num;
q.push(h);
sum2++;
}
}
h=g;
if(h.index<6)
{
c=h.str[h.index];h.str[h.index]=h.str[h.index+3];h.str[h.index+3]=c;
h.index+=3;
if(!h.mark){res1[cnt1].now=2;res1[cnt1].fa=h.num;h.num=cnt1;cnt1++;}
else {res2[cnt2].now=2;res2[cnt2].fa=h.num;h.num=cnt2;cnt2++;}
int t=KT(h.str);
if(vis1[t]==-1&&!h.mark)
{
vis1[t]=h.num;
q.push(h);
sum1++;
}
else if(vis2[t]==-1&&h.mark)
{
vis2[t]=h.num;
q.push(h);
sum2++;
}
}
h=g;
if(h.index>2)
{
c=h.str[h.index];h.str[h.index]=h.str[h.index-3];h.str[h.index-3]=c;
h.index-=3;
if(!h.mark){res1[cnt1].now=1;res1[cnt1].fa=h.num;h.num=cnt1;cnt1++;}
else {res2[cnt2].now=1;res2[cnt2].fa=h.num;h.num=cnt2;cnt2++;}
int t=KT(h.str);
if(vis1[t]==-1&&!h.mark)
{
vis1[t]=h.num;
q.push(h);
sum1++;
}
else if(vis2[t]==-1&&h.mark)
{
vis2[t]=h.num;
q.push(h);
sum2++;
}
}
if(sum1==0||sum2==0)
return false;
}
return false;
}
int main()
{
int i,j,k,kk,t,x,y,z;
while(scanf("%s",ss)!=EOF)
{
if(ss[0]=='x')x=0;
for(i=1;i<9;i++)
{
scanf("%s",ss+i);
if(ss[i]=='x') x=i;
}
ans1=ans2=-1;
memset(vis1,-1,sizeof(vis1));
memset(vis2,-1,sizeof(vis2));
res1[0].now=res2[0].now=-1;
if(bfs(ss,x))
{
x=0;
if(res2[ans2].now==-1&&res1[ans1].now==-1)
{
printf("lr\n");
continue;
}
while(res2[ans2].now!=-1)
{
hehe[x++]=res2[ans2].now;
ans2=res2[ans2].fa;
}
for(i=x-1;i>=0;i--)
{
if(hehe[i]==1)printf("u");
if(hehe[i]==2)printf("d");
if(hehe[i]==3)printf("l");
if(hehe[i]==4)printf("r");
}
while(res1[ans1].now!=-1)
{
if(res1[ans1].now==1)printf("d");
if(res1[ans1].now==2)printf("u");
if(res1[ans1].now==3)printf("r");
if(res1[ans1].now==4)printf("l");
ans1=res1[ans1].fa;
}
}
else
printf("unsolvable");
printf("\n");
}
return 0;
}
相关文章推荐
- 八数码第四境界——暴力反向BFS+康托展开判重+打表+回溯记录路径
- 八数码第七境界——A*之曼哈顿+康托展开判重+回溯记录路径+逆序数判无解
- 回溯路径的记录
- 八数码第三境界——暴力反向BFS+康托展开判重+打表
- sdut oj 3058 路线冲突问题(BFS+记录路径算法,回溯路径 )
- HDU 1043 Eight(八数码第五境界|A*+哈希+简单估价函数+打表)
- Pots(bfs+路径记录与回溯)
- HDOJ 5092 Seam Carving(动态规划,回溯,记录路径)
- 【PAT1018】 Public Bike Management 单源最短路径&路径记录回溯
- poj--3984--迷宫问题(bfs+路径记录)
- 实验室进度记录之网格化场景合并路径
- uvaoj 116 Unidirectional TSP 动态规划记录字典序最小路径
- 新年趣事之打牌(01背包+记录路径)
- HDU 1160 FatMouse's Speed DP 路径回溯
- POJ 1751 Highways (最小生成树+记录路径)
- hdu1074 状态压缩dp 记录路径
- 从路径uri加载Bitmap,缩小图片到指定大小的方法记录
- bzoj3445[Usaco2014 Feb] Roadblock 最短路(记录路径)
- shuoj-小6爱夜跑--Floyd记录多个最短路径
- 求任意大小矩阵两点之间的最短路径(回溯)