本人在做八数码问题时用了map去重和双向广度优先搜索,但是一直超时。
最后找到原因是:
虽然双向广度优先搜素相对于单项广度优先搜索而言减少了搜索深度,降低了时间复杂度和空间复杂度,但是对于如果初始状态无法到达目标状态时,双向广度优先搜索将是单项广度优先搜索耗时的两倍,网上的博客都是(map去重,set去重,康托展开hash去重)+(BFS,DBFS,A*)几乎都没有考虑无法到达的情况,本人找了好久终于找到了直接判断能否到达的方法,所以就想着写篇博客啦。
虽然刘汝佳老师的紫书上的方法也可过,但是本方法更优啦。
这是紫书上的方法在学校OJ上所耗内存和时间。
这是用map去重+DBFS+特判所耗内存和时间
如果将map改用为hash_map的话,更优。
好啦废话不多说,我们开始吧!
对于判断八数码是否有解,我们只需看两种状态的逆序奇偶性是否相同,意思就是:
将一个状态表示成一维的形式,求出除0之外所有数字的逆序数之和,也就是每个数字前面比它大的 数字的个数的和,称为这个状态的逆序。
如果两个状态的逆序奇偶性相同,则可相互到达,否则不可相互到达。(这里是剽窃别人的哈哈啊哈,放下链接----> (https://blog.csdn.net/hnust_xiehonghao/article/details/7951173)
int nixu()
{
int num1=0,num2=0;
for(int i=1;i<9;i++)
{
if(qow.map[i]=='0')
continue;
for(int j=0;j<i;j++)
{
if(qow.map[j]>qow.map[i])
num1++;
}
}
for(int i=1;i<9;i++)
{
if(out.map[i]=='0')
continue;
for(int j=0;j<i;j++)
{
if(out.map[j]>out.map[i])
num2++;
}
}
if(num1%2==0&&num2%2==0)
return 1;
if(num1%2!=0&&num2%2!=0)
return 1;
return 0;
}
这样我们就不用在无解的情况下耗费时间了,避免了DBFS的缺陷。
然后就是用map去重+DBFS了,完整代码如下:
#include<iostream>
#include<cstdio>
#include<queue>
#include<map>
#include<cstring>
using namespace std;
struct node{
int num,x,y,cnt;
char map[15];
}qow,out;
int fxy[4][2]={{1,0},{-1,0},{0,1},{0,-1}};
queue<node>q1,q2;
map<string,int>m1,m2;
int bfs()
{
while(!q1.empty()||!q2.empty())
{
if((!q1.empty()&&q1.size()<q2.size())||(!q1.empty()&&q2.empty()))
{
node emp=q1.front();
q1.pop();
if(m2[emp.map]) return emp.cnt+m2[emp.map];
for(int i=0;i<4;i++)
{
node now=emp;
int nowx=now.num/3+fxy[i][0];
int nowy=now.num%3+fxy[i][1];
int nowz=nowx*3+nowy;
if(nowx>=0&&nowx<3&&nowy>=0&&nowy<3&&(now.x!=-fxy[i][0]||now.y!=-fxy[i][1]))
{
swap(now.map[nowz],now.map[now.num]);
now.num=nowz;
now.x=fxy[i][0];
now.y=fxy[i][1];
now.cnt++;
if(!m1[now.map])
{
q1.push(now);
m1[now.map]=now.cnt;
}
}
}
}
else if((!q2.empty()&&q1.size()>=q2.size())||(!q2.empty()&&q1.empty()))
{
node emp1=q2.front();
q2.pop();
if(m1[emp1.map]) return emp1.cnt+m1[emp1.map];
for(int i=0;i<4;i++)
{
node now=emp1;
int nowx=now.num/3+fxy[i][0];
int nowy=now.num%3+fxy[i][1];
int nowz=nowx*3+nowy;
if(nowx>=0&&nowx<3&&nowy>=0&&nowy<3&&(now.x!=-fxy[i][0]||now.y!=-fxy[i][1]))
{
swap(now.map[nowz],now.map[now.num]);
now.num=nowz;
now.x=fxy[i][0];
now.y=fxy[i][1];
now.cnt++;
if(!m2[now.map])
{
q2.push(now);
m2[now.map]=now.cnt;
}
}
}
}
}
return -1;
}
int nixu()
{
int num1=0,num2=0;
for(int i=1;i<9;i++)
{
if(qow.map[i]=='0')
continue;
for(int j=0;j<i;j++)
{
if(qow.map[j]>qow.map[i])
num1++;
}
}
for(int i=1;i<9;i++)
{
if(out.map[i]=='0')
continue;
for(int j=0;j<i;j++)
{
if(out.map[j]>out.map[i])
num2++;
}
}
if(num1%2==0&&num2%2==0)
return 1;
if(num1%2!=0&&num2%2!=0)
return 1;
return 0;
}
int main(void)
{
while(~scanf("%c",&qow.map[0]))
{
getchar();
qow.cnt=0;
while(!q1.empty())
q1.pop();
while(!q2.empty())
q2.pop();
m1.clear();
m2.clear();
for(int i=1;i<9;i++)
{
scanf("%c",&qow.map[i]);
getchar();
if(qow.map[i]=='0')
{
qow.num=i;
}
}
qow.x=-2,qow.y=-2;
for(int i=0;i<9;i++)
{
scanf("%c",&out.map[i]);
getchar();
if(out.map[i]=='0')
out.num=i;
}
out.cnt=0,out.x=-2,out.y=-2;
if(nixu())
{
q1.push(qow);
q2.push(out);
m1[qow.map]=0;
m2[out.map]=0;
if(strcmp(qow.map,out.map)==0)
printf("0\n");
else cout<<bfs()<<endl;
}
else cout<<"-1"<<endl;
}
return 0;
}
蒟蒻一枚,第一次写博客,欢迎各位大佬指正。^ _ ^