接上文宽度优先搜索,虽然深度优先和宽度优先在理论上的差别不大,但是在最终的测试中我还是遇到了一些问题,导致26步计算不出来,只能用了一个中间状态来验证了一下思路正确而已。
这里先写一下自己的疑惑
假如0移动到target为目标状态,那么容易得到路径①为正确最短路径,但是在代码中初始0节点扩展时可能并不是向着下扩展,而是先向右扩展,那么会首先走向路径②,此时会深度优先会优先扩展路径②,这个时候假如沿着路径②走会产生两种错误,在本代码的运行结果中均有同样的错误产生。
- 在到达最大深度之前走到target,那么此时根据代码的判断已经找到路径,这个时候就会跳出整个while循环,进而输出②路径,但是②路径不是最优路径,当然这个错误是可以优化的,就是让while跑完,并不在找到一个解后就结束,然后将所有解都记录在一个STL中,最后对比路径长度,得到最短路径。但是又要涉及到第二个问题。
- 假设路径②走到第三步,也就是target节点的前一个节点就结束了,此时range刚好达到最大,这个时候路径②的深度优先就会被终止,进行其他路径的尝试,但是这个时候会产生一个巨大的问题,target的上一个节点已经被走过了,也就是说路径①走不了,因为访问当前节点是会先访问vis数组看当前节点是否被访问过,这个节点已经被访问了,所以路径②没有结果,路径①走不了。最后没有任何答案输出。
介于以上原因,我暂时没有想出第二个问题的解决方案,因此,我的深度优先算法存在一定的缺陷,所以我选择了到达目标过程中的一个中间过程,从初始状态到这个状态需要8步的状态来验证算法大致设计没有问题。结果如下,核心代码同BFS就不贴出来了。
直接贴全部代码:
#include"dfs.h"
void bfs(deque<Node>& openTable, deque<Node>& closeTable, int range) {
while (!openTable.empty()) {
closeTable.push_back(openTable.front());
openTable.pop_front();
//节点n的深度是否等于深度界限
if (closeTable.back().deep > range) {
continue;
}
else {
/*
广度优先搜索和深度优先搜索的唯一区别就是子节点放到open表的位置:
(1)广度优先搜索放到open表的后面
(2)深度优先搜索放到open表的前面
*/
for (int j = 1; j <= 4; j++) {
Node tempNode = closeTable.back();
move(tempNode, j);//扩展节点n
if (tempNode.code == "") {
continue;
}
if (check_Visit(tempNode)) {
continue;
}
tempNode.parent = closeTable.back().code;
openTable.push_front(tempNode); //把其后裔节点放入OPEN表的前端
if (isGoal(tempNode)) {//是否有任何后继节点为目标节点
cout << "成功,深度优先找到结果:" << endl;
showAnswer(closeTable);
return;//break;
}
}
}
}
}
int main() {
clock_t start, finish;
start = clock();
init_Fact();
string originString = "724506831";
Node originNode;
deque<Node> openTable, closeTable;//open存放未扩展节点,closed存放已扩展节点
int range = 10;//深度界限
originNode.code = originString;
originNode.deep = 0;
check_Visit(originNode);
openTable.push_back(originNode);
bfs(openTable, closeTable, range);
cout << "open表使用大小:" << openTable.size() << endl;
cout << "close表使用大小:" << closeTable.size() << endl;
finish = clock();
cout << (finish - start) << "毫秒" << endl;
//system("pause");
return 0;
}
#pragma once
#include<iostream>
#include<ctime>
#include<queue>
#include<cstring>
#include<list>
using namespace std;
const string GOAL = "254306781"; //012345678
int vis[362880 + 5], hashString[9];
struct Node {
string code;
string parent;
int deep;
};
Node move(Node& tempNode, int x) {
string::size_type loc;
for (int i = 0; i < 9; i++) {
if (tempNode.code[i] == '0') {
loc = i;//0的位置,从0开始计数
}
}
tempNode.deep++;
if (x == 1) {//上移
if (loc >= 3) {
char tempString = tempNode.code[loc];//找到空格
tempNode.code[loc] = tempNode.code[loc - 3];
tempNode.code[loc - 3] = tempString;
}
else {
tempNode.code = "";
}
}
else if (x == 2) {//下移
if (loc <= 5) {
char tempString = tempNode.code[loc];//找到空格
tempNode.code[loc] = tempNode.code[loc + 3];
tempNode.code[loc + 3] = tempString;
}
else {
tempNode.code = "";
}
}
else if (x == 3) {//左移
if (loc != 0 && loc != 3 && loc != 6) {
char tempString = tempNode.code[loc];//找到空格
tempNode.code[loc] = tempNode.code[loc - 1];
tempNode.code[loc - 1] = tempString;
}
else {
tempNode.code = "";
}
}
else if (x == 4) {//右移
if (loc != 2 && loc != 5 && loc != 8) {
char tempString = tempNode.code[loc];//找到空格
tempNode.code[loc] = tempNode.code[loc + 1];
tempNode.code[loc + 1] = tempString;
}
else {
tempNode.code = "";
}
}
return tempNode;
}
bool isGoal(Node tempNode) {//判断是否为最终的目标节点
if (tempNode.code == GOAL) {
return true;
}
return false;
}
void show(string tempString) {//输出当前字符串
if (!tempString.empty()) {
cout << tempString[0] << " " << tempString[1] << " " << tempString[2] << endl
<< tempString[3] << " " << tempString[4] << " " << tempString[5] << endl
<< tempString[6] << " " << tempString[7] << " " << tempString[8] << endl << endl;
}
else {
cout << "空的" << endl;
}
}
//路径
deque<Node> findPath(deque<Node>& closed) {
deque<Node> dequeList;
Node temp = closed.back();
dequeList.push_back(temp);
//closeTable表从后往前,根据parent值找到路径
for (int i = closed.size() - 1; i >= 0; i--) {
if (temp.parent == closed.at(i).code) {
dequeList.push_back(closed.at(i));
temp = closed.at(i);
}
}
//cout << dequeList.size() << endl;
return dequeList;
}
void showAnswer(deque<Node>& closed) {
deque<Node> way(findPath(closed));
cout << "共需要" << way.size() << "步" << endl;
for (int i = way.size() - 1; i >= 0; i--){
show(way.at(i).code);
}
//输出目标
show(GOAL);
}
void init_Fact() {
hashString[0] = 1;
for (int i = 1; i < 9; ++i) hashString[i] = hashString[i - 1] * i;
memset(vis, 0, sizeof(0));
}
bool check_Visit(Node temp) {
int nowString[9];
int code = 0;
for (int i = 0; i < 9; i++) {
nowString[i] = temp.code[i] - '0';
}
for (int i = 0; i < 9; i++) {
int cnt = 0;
for (int j = i + 1; j < 9; ++j) if (nowString[j] < nowString[i]) cnt++;
code += hashString[8 - i] * cnt;
}
if (vis[code]) return true;
else vis[code] = 1;
return false;
}