八数码第一境界——暴力反向BFS+存状态
2017-12-13 01:42
288 查看
这题首先会遇到一个问题:BFS无法实施
为什么会无法实施?
![](https://img-blog.csdn.net/20171213014514239?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcXFfMzY1MjM2Njc=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
正常情况,x从队列中取出,8、6入队
8从队列中取出,x和8交换,7、5入队
这个时候下一个要出队列的是6,但是你x在8原来的位置,怎么实施交换?
所以队列中应该入的是状态,可能很抽象,但是下面的图不抽象。
![](https://img-blog.csdn.net/20171213015615336?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcXFfMzY1MjM2Njc=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
我们还是看6要出队列的时候的情况,就是第三行第一个。我们发现他可以出队列了。出队列,向左移动的一个情况以及向右移动的一个情况被添加到队列底端。
如何存这个队列?
采用结构体。
struct node
{
string str;
vector<int>res;
int index;
};
map<string,int> mp;
vector<int>res;
str一维数组,把二维数组降了一维。
vector用来存你历次的移动方向。
index用来存当前str中的x在哪个位置。
map用来判断当前这种状态我们是否已经走过了。
具体BFS的方法?
while(!q.empty())
{
g=q.front();q.pop();
if(g.str==ss)
{
res=g.res;
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++;
h.res.push_back(4);
if(mp[h.str]==0)
{
mp[h.str]=true;
q.push(h);
}
}
第三行,出队列。
接下来的if判断,用来判断是否当前这个状态和我们要求的一样,如果是,那代表已经找到了,返回true。
h=g,把当前队首元素给h,因为当前的队首元素后面还要用,这里仅仅是代表了他右移的可能性。
接下来if判断,如果他不是最后一列,我们进入这个if,而且不用想在不是最后一列的情况下我们是可以右移的。
和右边的数交换。
x所在string中的位置增加一位。
4存入操作,4代表的是右移。
如果这种状态的键取出来的值是0,那就代表这种状态以前没走过,可以入队列,并且把这个状态设置为已走过。
完毕。
接下来几个方向也是几乎一样的操作。
全部代码
char s[101];
struct node
{
string str;
vector<int>res;
int index;
};
map<string,int> mp;
vector<int>res;
bool bfs(string ss)
{
char c;
queue<node> q;
while(!q.empty())q.pop();
node g,h;
g.str="12345678x";g.res.clear();g.index=8;
q.push(g);
while(!q.empty())
{
g=q.front();q.pop();
if(g.str==ss)
{
res=g.res;
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++;
h.res.push_back(4);
if(mp[h.str]==0)
{
mp[h.str]=true;
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--;
h.res.push_back(3);
if(!mp[h.str])
{
mp[h.str]=true;
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;
h.res.push_back(2);
if(!mp[h.str])
{
mp[h.str]=true;
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;
h.res.push_back(1);
if(!mp[h.str])
{
mp[h.str]=true;
q.push(h);
}
}
}
return false;
}
int main()
{
int i,j,k,kk,t,x,y,z;
while(scanf("%s",s)!=EOF)
{
mp.clear();
for(i=1;i<9;i++)
scanf("%s",s+i);
string ss(s);
if(bfs(ss))
for(i=res.size()-1;i>=0;i--)
{
if(res[i]==1)printf("d");
if(res[i]==2)printf("u");
if(res[i]==3)printf("r");
if(res[i]==4)printf("l");
}
else
printf("unsolvable");
printf("\n");
}
return 0;
}
为什么会无法实施?
正常情况,x从队列中取出,8、6入队
8从队列中取出,x和8交换,7、5入队
这个时候下一个要出队列的是6,但是你x在8原来的位置,怎么实施交换?
所以队列中应该入的是状态,可能很抽象,但是下面的图不抽象。
我们还是看6要出队列的时候的情况,就是第三行第一个。我们发现他可以出队列了。出队列,向左移动的一个情况以及向右移动的一个情况被添加到队列底端。
如何存这个队列?
采用结构体。
struct node
{
string str;
vector<int>res;
int index;
};
map<string,int> mp;
vector<int>res;
str一维数组,把二维数组降了一维。
vector用来存你历次的移动方向。
index用来存当前str中的x在哪个位置。
map用来判断当前这种状态我们是否已经走过了。
具体BFS的方法?
while(!q.empty())
{
g=q.front();q.pop();
if(g.str==ss)
{
res=g.res;
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++;
h.res.push_back(4);
if(mp[h.str]==0)
{
mp[h.str]=true;
q.push(h);
}
}
第三行,出队列。
接下来的if判断,用来判断是否当前这个状态和我们要求的一样,如果是,那代表已经找到了,返回true。
h=g,把当前队首元素给h,因为当前的队首元素后面还要用,这里仅仅是代表了他右移的可能性。
接下来if判断,如果他不是最后一列,我们进入这个if,而且不用想在不是最后一列的情况下我们是可以右移的。
和右边的数交换。
x所在string中的位置增加一位。
4存入操作,4代表的是右移。
如果这种状态的键取出来的值是0,那就代表这种状态以前没走过,可以入队列,并且把这个状态设置为已走过。
完毕。
接下来几个方向也是几乎一样的操作。
全部代码
char s[101];
struct node
{
string str;
vector<int>res;
int index;
};
map<string,int> mp;
vector<int>res;
bool bfs(string ss)
{
char c;
queue<node> q;
while(!q.empty())q.pop();
node g,h;
g.str="12345678x";g.res.clear();g.index=8;
q.push(g);
while(!q.empty())
{
g=q.front();q.pop();
if(g.str==ss)
{
res=g.res;
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++;
h.res.push_back(4);
if(mp[h.str]==0)
{
mp[h.str]=true;
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--;
h.res.push_back(3);
if(!mp[h.str])
{
mp[h.str]=true;
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;
h.res.push_back(2);
if(!mp[h.str])
{
mp[h.str]=true;
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;
h.res.push_back(1);
if(!mp[h.str])
{
mp[h.str]=true;
q.push(h);
}
}
}
return false;
}
int main()
{
int i,j,k,kk,t,x,y,z;
while(scanf("%s",s)!=EOF)
{
mp.clear();
for(i=1;i<9;i++)
scanf("%s",s+i);
string ss(s);
if(bfs(ss))
for(i=res.size()-1;i>=0;i--)
{
if(res[i]==1)printf("d");
if(res[i]==2)printf("u");
if(res[i]==3)printf("r");
if(res[i]==4)printf("l");
}
else
printf("unsolvable");
printf("\n");
}
return 0;
}
相关文章推荐
- 八数码第二境界——暴力反向BFS+康托展开判重
- 八数码第三境界——暴力反向BFS+康托展开判重+打表
- 暑期第一弹<搜索> B - Dungeon Master(三维BFS,6个状态)
- UVA 810 A Dicey Promblem 筛子难题 (暴力BFS+状态处理)
- hdu 1043 反向bfs标号+dfs查询+stl+状态压缩
- HDU-1043:Eight(八数码+bfs(反向或A*))
- CF 474C Captain Marmot[暴力枚举 || bfs状态压缩 ]
- POJ 1077 八数码(康托展开+暴力bfs)
- 八数码第四境界——暴力反向BFS+康托展开判重+打表+回溯记录路径
- NPU17届程序设计 1571 八数码问题 暴力BFS
- POJ 3221:Diamond Puzzle(六数码 反向bfs)
- poj 1077 Eight 八数码问题( 康拓展开+BFS状态压缩)
- 八数码问题bfs暴力破解(java实现)
- [数据结构]八数码(暴力,解答树,BFS+hash)
- 【BFS】由八数码问题的BFS解法引出的三种BFS经典状态判重方法
- hdu 4770 13 杭州 现场 A - Lights Against Dudely 暴力 bfs 状态压缩DP 难度:1
- hdu 1044 Collect More Jewels【暴力Bfs+状态压缩】
- FZU--2188--过河(bfs暴力条件判断)
- ACM之八数码问题----BFS搜索----数独游戏的模拟(中)
- HDU4845(SummerTrainingDay02-C 状态压缩bfs)