八数码第四境界——暴力反向BFS+康托展开判重+打表+回溯记录路径
2017-12-13 22:34
435 查看
(请先看前面3重境界)
由于第三重境界要开一个vector来嵌套许多vector来记录路径,那绝对是开销很大。所以我们采用回溯记录路径。
思路:
原来我们是采用康托展开,比如求出12345678x在全排列的第几个(这里无疑是第一个),用来判断这种状态是否已经到达过了,这里就是vis[1]=1代表已经访问过,vis[1]=0代表未访问过。在每次访问以后都置为1。而现在我们这里不一样了。我们存放的是层数。我们这里想要的是路径吧?所以说这里指的就是在这条路径上的第几个,我们的做法就是在最后找到以后,根据这个第几个,来逐一找到上一个,直到找到终点。以前我们每种状态维护的是一个路径,我们这里只需要维护一个操作就可以了。只要我们能把每种状态的路径,和上一种状态的路径,想办法关联起来,就可以了。
用来找到关联的结构体:
1. struct res
2. {
3. int now,fa;
}res
;
now存放的就是当前的操作(上下左右),fa就是这条路径上上一个状态的操作在这个res数组中存放的地方。就比如说我现在是这个数组的第10个,我的操作是上,我的fa是7,就代表我上一个操作被存放在了7,我们不断去取即可。所以我们一旦让一个点入栈了,也同时会在这个数组的尾端添加一个。赋予他当前的操作是什么,以及这条路径上上一个操作所存放的位置。这个怎么得知呢?因为我们就是通过上一种状态得出下一种状态的,所以我们只需要在上一种状态得出下一种状态的过程中,把他上一种状态所在这个数组中的位置给他,交给他去维护了。所以我们可以得知,这个res数组,并不是有序的。什么意思呢?并不是说这个状态的操作在这里,下一个状态的操作在这个数组的下一个位置,而是通过fa来进行关联。
上个图:
![](https://oscdn.geek-share.com/Uploads/Images/Content/201712/af190aa1a526704837558311ba5df7ab)
此外,我们上面讲的康托展开,vis[某个节点对应的康托值] = 这个res集合中的某一位,再以此为依据就能回溯出之前的路径了。
讲了这么多理论,具体看看细化的实现。
1. if((h.index+1)%3!=0)
2. {
3. c=h.str[h.index];h.str[h.index]=h.str[h.index+1];h.str[h.index+1]=c;
4. h.index++;
5. res[cnt].now=4;res[cnt].fa=h.pos;h.pos=cnt;cnt++;
6. int t=KT(h.str);
7. if(vis[t]==-1)
8. {
9. vis[t]=cnt-1;
10. q.push(h);
11. }
12. }
if语句判断如果不是在最后一列,那就肯定就可以右移。
下一行,和右边那个数进行交换。
h.index指的是x在状态中的位置
res[cnt].now=4,4指代的是右移操作
res[cnt].fa=h.pos这个指的是你上一个状态所在这个res数组的位置赋给你当前状态去维护
h.pos=cnt这是你当前状态所在这个res数组的位置
cnt++你插入了一个数,自然要++,不然接下来还用不用了
最后如果这个位置没有访问过,那么这个状态在vis中的值,也被置为和你当前h.pos位置一样的值。为什么这里也要作文章,因为最后你输出的时候你肯定要根据所要求的结果在res中定位,那你定位的依据是什么?只能以序列通过求康托值得出在vis中的位置,再去取得这个值。
1. if(vis[t]!=-1)
2.
{
3. t = vis[t];
4.
while(res[t].now!=-1)
5. {
6.
if(res[t].now==1)printf("d");
7. if(res[t].now==2)printf("u");
8.
if(res[t].now==3)printf("r");
9. if(res[t].now==4)printf("l");
10.
t=res[t].fa;
11. }
12.
}
13. else
14.
printf("unsolvable");
如果vis[t]!=-1,那么就是这种状态肯定是有的,而我们在这个里面存储了他在res中的位置,所以再通过fa一步步回推,得出了序列。
全部代码
#define N 512345
char ss[10];
struct node
{
char str[10];
int pos;
int index;
};
struct res
{
int now,fa;
}res
;
int vis
;
int fac[] = {1,1,2,6,24,120,720,5040,40320};
int over,cnt;
int ans
;
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 c;
queue<node> q;
while(!q.empty())q.pop();
over = KT(ss);
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.pos=0;g.index=8;
int t=KT(g.str);
vis[t] = 0;
q.push(g);
cnt=1;
while(!q.empty())
{
g=q.front();q.pop();
int t = KT(g.str);
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++;
res[cnt].now=4;res[cnt].fa=h.pos;h.pos=cnt;cnt++;
int t=KT(h.str);
if(vis[t]==-1)
{
vis[t]=cnt-1;
q.push(h);
}
}
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--;
res[cnt].now=3;res[cnt].fa=h.pos;h.pos=cnt;cnt++;
int t=KT(h.str);
if(vis[t]==-1)
{
vis[t]=cnt-1;
q.push(h);
}
}
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;
res[cnt].now=2;res[cnt].fa=h.pos;h.pos=cnt;cnt++;
int t=KT(h.str);
if(vis[t]==-1)
{
vis[t]=cnt-1;
q.push(h);
}
}
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;
res[cnt].now=1;res[cnt].fa=h.pos;h.pos=cnt;cnt++;
int t=KT(h.str);
if(vis[t]==-1)
{
vis[t]=cnt-1;
q.push(h);
}
}
}
return false;
}
int main()
{
int i,j,k,kk,t,x,y,z;
memset(vis,-1,sizeof(vis));
res[0].now=-1;
bfs();
while(scanf("%s",ss)!=EOF)
{
for(i=1;i<9;i++)
scanf("%s",ss+i);
t = KT(ss);
if(vis[t]!=-1)
{
t = vis[t];
while(res[t].now!=-1)
{
if(res[t].now==1)printf("d");
if(res[t].now==2)printf("u");
if(res[t].now==3)printf("r");
if(res[t].now==4)printf("l");
t=res[t].fa;
}
}
else
printf("unsolvable");
printf("\n");
}
return 0;
}
由于第三重境界要开一个vector来嵌套许多vector来记录路径,那绝对是开销很大。所以我们采用回溯记录路径。
思路:
原来我们是采用康托展开,比如求出12345678x在全排列的第几个(这里无疑是第一个),用来判断这种状态是否已经到达过了,这里就是vis[1]=1代表已经访问过,vis[1]=0代表未访问过。在每次访问以后都置为1。而现在我们这里不一样了。我们存放的是层数。我们这里想要的是路径吧?所以说这里指的就是在这条路径上的第几个,我们的做法就是在最后找到以后,根据这个第几个,来逐一找到上一个,直到找到终点。以前我们每种状态维护的是一个路径,我们这里只需要维护一个操作就可以了。只要我们能把每种状态的路径,和上一种状态的路径,想办法关联起来,就可以了。
用来找到关联的结构体:
1. struct res
2. {
3. int now,fa;
}res
;
now存放的就是当前的操作(上下左右),fa就是这条路径上上一个状态的操作在这个res数组中存放的地方。就比如说我现在是这个数组的第10个,我的操作是上,我的fa是7,就代表我上一个操作被存放在了7,我们不断去取即可。所以我们一旦让一个点入栈了,也同时会在这个数组的尾端添加一个。赋予他当前的操作是什么,以及这条路径上上一个操作所存放的位置。这个怎么得知呢?因为我们就是通过上一种状态得出下一种状态的,所以我们只需要在上一种状态得出下一种状态的过程中,把他上一种状态所在这个数组中的位置给他,交给他去维护了。所以我们可以得知,这个res数组,并不是有序的。什么意思呢?并不是说这个状态的操作在这里,下一个状态的操作在这个数组的下一个位置,而是通过fa来进行关联。
上个图:
此外,我们上面讲的康托展开,vis[某个节点对应的康托值] = 这个res集合中的某一位,再以此为依据就能回溯出之前的路径了。
讲了这么多理论,具体看看细化的实现。
1. if((h.index+1)%3!=0)
2. {
3. c=h.str[h.index];h.str[h.index]=h.str[h.index+1];h.str[h.index+1]=c;
4. h.index++;
5. res[cnt].now=4;res[cnt].fa=h.pos;h.pos=cnt;cnt++;
6. int t=KT(h.str);
7. if(vis[t]==-1)
8. {
9. vis[t]=cnt-1;
10. q.push(h);
11. }
12. }
if语句判断如果不是在最后一列,那就肯定就可以右移。
下一行,和右边那个数进行交换。
h.index指的是x在状态中的位置
res[cnt].now=4,4指代的是右移操作
res[cnt].fa=h.pos这个指的是你上一个状态所在这个res数组的位置赋给你当前状态去维护
h.pos=cnt这是你当前状态所在这个res数组的位置
cnt++你插入了一个数,自然要++,不然接下来还用不用了
最后如果这个位置没有访问过,那么这个状态在vis中的值,也被置为和你当前h.pos位置一样的值。为什么这里也要作文章,因为最后你输出的时候你肯定要根据所要求的结果在res中定位,那你定位的依据是什么?只能以序列通过求康托值得出在vis中的位置,再去取得这个值。
1. if(vis[t]!=-1)
2.
{
3. t = vis[t];
4.
while(res[t].now!=-1)
5. {
6.
if(res[t].now==1)printf("d");
7. if(res[t].now==2)printf("u");
8.
if(res[t].now==3)printf("r");
9. if(res[t].now==4)printf("l");
10.
t=res[t].fa;
11. }
12.
}
13. else
14.
printf("unsolvable");
如果vis[t]!=-1,那么就是这种状态肯定是有的,而我们在这个里面存储了他在res中的位置,所以再通过fa一步步回推,得出了序列。
全部代码
#define N 512345
char ss[10];
struct node
{
char str[10];
int pos;
int index;
};
struct res
{
int now,fa;
}res
;
int vis
;
int fac[] = {1,1,2,6,24,120,720,5040,40320};
int over,cnt;
int ans
;
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 c;
queue<node> q;
while(!q.empty())q.pop();
over = KT(ss);
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.pos=0;g.index=8;
int t=KT(g.str);
vis[t] = 0;
q.push(g);
cnt=1;
while(!q.empty())
{
g=q.front();q.pop();
int t = KT(g.str);
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++;
res[cnt].now=4;res[cnt].fa=h.pos;h.pos=cnt;cnt++;
int t=KT(h.str);
if(vis[t]==-1)
{
vis[t]=cnt-1;
q.push(h);
}
}
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--;
res[cnt].now=3;res[cnt].fa=h.pos;h.pos=cnt;cnt++;
int t=KT(h.str);
if(vis[t]==-1)
{
vis[t]=cnt-1;
q.push(h);
}
}
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;
res[cnt].now=2;res[cnt].fa=h.pos;h.pos=cnt;cnt++;
int t=KT(h.str);
if(vis[t]==-1)
{
vis[t]=cnt-1;
q.push(h);
}
}
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;
res[cnt].now=1;res[cnt].fa=h.pos;h.pos=cnt;cnt++;
int t=KT(h.str);
if(vis[t]==-1)
{
vis[t]=cnt-1;
q.push(h);
}
}
}
return false;
}
int main()
{
int i,j,k,kk,t,x,y,z;
memset(vis,-1,sizeof(vis));
res[0].now=-1;
bfs();
while(scanf("%s",ss)!=EOF)
{
for(i=1;i<9;i++)
scanf("%s",ss+i);
t = KT(ss);
if(vis[t]!=-1)
{
t = vis[t];
while(res[t].now!=-1)
{
if(res[t].now==1)printf("d");
if(res[t].now==2)printf("u");
if(res[t].now==3)printf("r");
if(res[t].now==4)printf("l");
t=res[t].fa;
}
}
else
printf("unsolvable");
printf("\n");
}
return 0;
}
相关文章推荐
- 八数码第三境界——暴力反向BFS+康托展开判重+打表
- 八数码第五境界——双向BFS+康托展开判重+回溯记录路径
- 八数码第七境界——A*之曼哈顿+康托展开判重+回溯记录路径+逆序数判无解
- HDOJ 5092 Seam Carving(动态规划,回溯,记录路径)
- 八数码第一境界——暴力反向BFS+存状态
- sdut oj 3058 路线冲突问题(BFS+记录路径算法,回溯路径 )
- Pots(bfs+路径记录与回溯)
- 【PAT1018】 Public Bike Management 单源最短路径&路径记录回溯
- hdu3567 Eight II 康拓展开+打表+路径回溯+映射
- 八数码第二境界——暴力反向BFS+康托展开判重
- POJ 1122 反向建图Dijkstra+记录路径 输入格式坑
- 回溯路径的记录
- UVa - 624 - CD(0-1 + 记录路径)
- poj3984迷宫问题【bfs+记录路径】
- POJ1734 Sightseeing trip 【Floyd】+【最小环】+【路径记录】
- Log4j日志记录的相对路径问题与打印HQL
- poj 2488 A Knight's Journey(dfs+记录路径)
- C++中从文件末尾反向读取N行文件记录。
- log4j配置相对路径实现日志记录
- 循环问题2012蓝桥杯省赛第四题 奇怪的比赛(暴力解决)