八数码问题求解(1)深度优先搜索

人工智能课,第一个实验就是八数码问题。老师让用3中方式都实现一遍,分别是广度优先搜索、深度优先搜索和启发式搜索。心塞╮(╯▽╰)╭。紧急补了一些数据结构的知识,就匆匆上阵。先分享深度优先搜索,后两篇我会分享广度优先搜索和启发式搜索的实现。

概念就不讲了,百度就行了。简单说一下我的实现:Situation类存储节点信息,包括父节点的code值(code是一个字符串,存储的是八数码的状态,比如“138427056”),当前节点的code值,以及深度(深度从0开始,即起始节点深度为0);在Test.cpp的main函数中,我定义了两个链表open和closed分别存放未被扩展的节点和被扩展的节点。深度优先,新生成的有效的子节点存放在open表的开头。每次扩展,拿open表的开头的那个节点来扩展,方法是把open表的头节点移动到closed表的末端,生成的最多4个有效的子节点存放在open表的开头。其他就是比较生成的节点和目标节点是否相等了。

以下代码在win8.1下VS2013中测试成功。

头文件Deep.h:

#include<iostream>
#include"queue"
#include"string"
#include<list>

using namespace std;

const string GOAL = "803214765";

class Situation{
private:
    
public:
    string father;
    string code;//当前状态
    int deep;
    Situation up();
    Situation down();
    Situation left();
    Situation right();
    bool isGoal();
    bool isInOpen(deque<Situation> &open);
    bool isInClosed(deque<Situation> &closed);
    void show() const;
    void show(string) const;
    void show_deque(deque<Situation> &) const;
    deque<Situation> showWay(deque<Situation> &closed);
    void showAnswer(deque<Situation> &closed);//显示解答
    Situation() :father(""), code(""), deep(-1){};
};

Deep.cpp:

#include"Deep.h"

Situation Situation::up(){
    string::size_type loc = code.find('0');//0的位置,从0开始计数
    Situation son;
    son.code = code;
    son.deep = deep + 1;
    if (loc>=3){
        char temp = son.code[loc];//即0
        son.code[loc] = son.code[loc - 3];
        son.code[loc-3] = temp;
    }
    else{
        son.code = "";
    }
    return son;
}

Situation Situation::down(){
    string::size_type loc = code.find('0');//0的位置,从0开始计数
    Situation son;
    son.code = code;
    son.deep = deep + 1;
    if (loc<=5){
        char temp = son.code[loc];//即0
        son.code[loc] = son.code[loc + 3];
        son.code[loc + 3] = temp;
    }
    else{
        son.code = "";
    }
    return son;
}

Situation Situation::left(){
    string::size_type loc = code.find('0');//0的位置,从0开始计数
    Situation son;
    son.code = code;
    son.deep = deep + 1;
    if (loc!=0&&loc!=3&&loc!=6){
        char temp = son.code[loc];//即0
        son.code[loc] = son.code[loc - 1];
        son.code[loc - 1] = temp;
    }
    else{
        son.code = "";
    }
    return son;
}

Situation Situation::right(){
    string::size_type loc = code.find('0');//0的位置,从0开始计数
    Situation son;
    son.code = code;
    son.deep = deep + 1;
    if (loc!=2&&loc!=5&&loc!=8){
        char temp = son.code[loc];//即0
        son.code[loc] = son.code[loc + 1];
        son.code[loc + 1] = temp;
    }
    else{
        son.code = "";
    }
    return son;
}

bool Situation::isGoal(){
    return code == GOAL;
}

bool Situation::isInOpen(deque<Situation> &open){
    /*deque<Situation>::iterator it = open.begin();
    while (it != open.end()){
        if (code == (*it).code){
            return true;
        }
        it++;
    }*/
    for (int i = 0; i < open.size();i++){
        if (code==open.at(i).code){
            return true;
        }
    }
    return false;
}

bool Situation::isInClosed(deque<Situation> &closed){
    /*deque<Situation>::iterator it = closed.begin();
    while (it!=closed.end()){
        if (code == (*it).code){
            return true;
        }
        it++;
    }*/
    for (int i = 0; i < closed.size(); i++){
        if (code == closed.at(i).code){
            return true;
        }
    }
    return false;
}

void Situation::show() const{
    if (!code.empty()){
        cout << code[0] << code[1] << code[2] << endl
            << code[3] << code[4] << code[5] << endl
            << code[6] << code[7] << code[8] << endl << endl;
    }
    else{
        cout << "空的" << endl;
    }
}

void Situation::show(string code) const{
    if (!code.empty()){
        cout << code[0] << code[1] << code[2] << endl
            << code[3] << code[4] << code[5] << endl
            << code[6] << code[7] << code[8] << endl << endl;
    }
    else{
        cout << "空的" << endl;
    }
}

void Situation::show_deque(deque<Situation> &m_deque) const{
    /*deque<Situation>::iterator it = m_deque.begin();
    while (it!=m_deque.end())
    {
        (*it).show();
        it++;
    }*/
    for (int i = 0; i < m_deque.size();i++){
        m_deque.at(i).show();
    }
}

//路径
deque<Situation> Situation::showWay(deque<Situation> &closed){
    //cout << closed.size() << endl;
    deque<Situation> dequeList;
    Situation temp = closed.back();
    dequeList.push_back(temp);

    //closed表从后往前,根据father值找到路径
    for (int i = closed.size()-1; i >= 0;i--){
        if (temp.father==closed.at(i).code){
            dequeList.push_back(closed.at(i));
            temp = closed.at(i);
        }
    }
    //cout << dequeList.size() << endl;
    return dequeList;
}

void Situation::showAnswer(deque<Situation> &closed){
    deque<Situation> way(showWay(closed));
    cout << "共需要" << way.size() << "步" << endl;
    for (int i = way.size() - 1; i >= 0; i--)
    {
        way.at(i).show();
    }
    //输出目标
    show(GOAL);
}

Test.cpp:

#include<iostream>
#include"Deep.h"

using namespace std;

void loop(deque<Situation> &open, deque<Situation> &closed, int range);

int main(){
    string original = "283164705";
    Situation first;
    deque<Situation> open, closed;//open存放未扩展节点,closed存放已扩展节点
    int range = 10;//深度界限

    first.code = original;
    first.deep = 0;
    open.push_back(first);
    loop(open,closed,range);
    return 0;
}

void loop(deque<Situation> &open, deque<Situation> &closed,int range){
    Situation a;
    int i = 0;
    while (!open.empty()){
        cout << i++ << endl;
        if (open.front().code == GOAL){
            cout << "成功:" << endl;
            a.showAnswer(closed);
            return;
        }
        if (open.empty()){
            cout << "失败" << endl;
            return;
        }
        closed.push_back(open.front());
        open.pop_front();
        //节点n的深度是否等于深度界限
        if (closed.back().deep == range){
            //loop(open,closed,range);不能用递归
            continue; 
        }
        else{
            //扩展节点n,把其后裔节点放入OPEN表的末端
            Situation son1 = closed.back().up();
            Situation son2 = closed.back().down();
            Situation son3 = closed.back().left();
            Situation son4 = closed.back().right();
            /*
            广度优先搜索和深度优先搜索的唯一区别就是子节点放到open表的位置:
            (1)广度优先搜索放到open表的后面
            (2)深度优先搜索放到open表的前面
            */
            if (!son1.code.empty()){
                if (!son1.isInOpen(open)&&!son1.isInClosed(closed)){
                    son1.father = closed.back().code;
                    open.push_front(son1);
                }
            }
            if (!son2.code.empty()){
                if (!son2.isInOpen(open) && !son2.isInClosed(closed)){
                    son2.father = closed.back().code;
                    open.push_front(son2);
                }
            }
            if (!son3.code.empty()){
                if (!son3.isInOpen(open) && !son3.isInClosed(closed)){
                    son3.father = closed.back().code;
                    open.push_front(son3);
                }
            }
             if (!son4.code.empty()){
                if (!son4.isInOpen(open) && !son4.isInClosed(closed)){
                    son4.father = closed.back().code;
                    open.push_front(son4);
                }
                
            }
            //是否有任何后继节点为目标节点
            if (son1.isGoal()){
                cout << "后继节点中有目标节点:" << endl;
                son1.showAnswer(closed);
                break;
            }
            if (son2.isGoal()){
                cout << "后继节点中有目标节点:" << endl;
                son2.showAnswer(closed);
                break;
            }
            if (son3.isGoal()){
                cout << "后继节点中有目标节点:" << endl;
                son3.showAnswer(closed);
                break;
            }
            if (son4.isGoal()){
                cout << "后继节点中有目标节点:" << endl;
                son4.showAnswer(closed);
                break;
            }
        }
    }
}
阅读 8.5k

推荐阅读
五毛程序员
用户专栏

C++,java,html5

3 人关注
13 篇文章
专栏主页