八數碼問題求解(1)深度優先搜索

人工智能課,第一個實驗就是八數碼問題。老師讓用3中方式都實現一遍,分別是廣度優先搜索、深度優先搜索和啓發式搜索。心塞╮(╯▽╰)╭。緊急補了一些數據結構的知識,就匆匆上陣。先分享深度優先搜索,後兩篇我會分享廣度優先搜索和啓發式搜索的實現。ios

概念就不講了,百度就好了。簡單說一下個人實現:Situation類存儲節點信息,包括父節點的code值(code是一個字符串,存儲的是八數碼的狀態,好比「138427056」),當前節點的code值,以及深度(深度從0開始,即起始節點深度爲0);在Test.cpp的main函數中,我定義了兩個鏈表open和closed分別存放未被擴展的節點和被擴展的節點。深度優先,新生成的有效的子節點存放在open表的開頭。每次擴展,拿open表的開頭的那個節點來擴展,方法是把open表的頭節點移動到closed表的末端,生成的最多4個有效的子節點存放在open表的開頭。其餘就是比較生成的節點和目標節點是否相等了。數據結構

如下代碼在win8.1下VS2013中測試成功。函數

頭文件Deep.h:oop

#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;
            }
        }
    }
}
相關文章
相關標籤/搜索