八数码问题的A*算法求解

  A*算法是启发式搜素算法中较为出名和高效的算法之一,其关键是对于启发式函数的实际,启发式函数h(x)需要尽可能的接近实际的 h(x) h ( x ) ∗ 。下面是人工智能八数码问题使用A*算法求解的源码放在博客上记录一下。程序使用放错位置的棋子的个数作为启发式函数。

#include <iostream>
#include <vector>
#include <queue>

using namespace std;


class Picture {
private:

    int **pictureArray = NULL;
    int hValue;
    int gValue;
    int fValue;
public:
    Picture *parente=NULL;
    int zeroRow, zeroColumn;
    static int rowSize, columnSize;

    static void setSize(int row, int column) {
        rowSize = row;
        columnSize = column;
    }

    Picture() {
        if (rowSize == 0 || columnSize == 0)
            throw "no init";
        pictureArray = new int *[rowSize];
        for (int i = 0; i < rowSize; ++i) {
            pictureArray[i] = new int[columnSize];
        }
        hValue = 0;
        gValue = 0;
        fValue = 0;
        setArray();
    }

    Picture(const Picture &sourse) {
        zeroRow = sourse.getZeroRow();
        zeroColumn = sourse.getZeroColumn();
        parente = sourse.parente;
        pictureArray = new int *[rowSize];
        for (int i = 0; i < rowSize; ++i) {
            pictureArray[i] = new int[columnSize];
        }
        for (int i = 0; i < rowSize; ++i)
            for (int j = 0; j < columnSize; ++j) {
                pictureArray[i][j] = sourse.getPicturePoint()[i][j];
            }
    }

    ~Picture() {
        delete[] pictureArray;
    }

    bool operator==(const Picture &source) const {
        for (int i = 0; i < rowSize; ++i)
            for (int j = 0; j < columnSize; ++j) {
                if (pictureArray[i][j] != source.getPicturePoint()[i][j])
                    return false;
            }
        return true;
    }

    void setArray() {
        for (int i = 0; i < rowSize; ++i) {
            for (int j = 0; j < columnSize; ++j) {
                cin >> pictureArray[i][j];
                if (pictureArray[i][j] == 0) {
                    zeroRow = i;
                    zeroColumn = j;
                }
            }
        }
    }


    /*
    * 设置启发式函数的值
    */
    void setHValue(const Picture &endPicture) {
        int result = 0;
        int **tempPicture = endPicture.getPicturePoint();
        for (int i = 0; i < rowSize; ++i)
            for (int j = 0; j < columnSize; ++j) {
                if (pictureArray[i][j] != tempPicture[i][j])
                    ++result;
            }
        hValue = result;
    }

    void updateFvalue() {
        fValue = hValue + gValue;
    }

    void setGvalue(int value) {
        gValue = value;
    }

    int **getPicturePoint() const {
        return pictureArray;
    }

    int getFValue() const {
        return fValue;
    }

    int getGvalue() const {
        return gValue;
    }

    int getZeroRow() const {
        return zeroRow;
    }

    int getZeroColumn() const {
        return zeroColumn;
    }

    void showPicture() const {
        for (int i = 0; i < rowSize; ++i) {
            for (int j = 0; j < columnSize - 1; ++j) {
                cout << pictureArray[i][j] << ' ';
            }
            cout << pictureArray[i][columnSize - 1] << endl;
        }
        cout<<endl;
    }
};


int inVector(vector<Picture *> const &theVector, Picture const &element) {
    for (int i = 0; i < theVector.size(); ++i)
        if (element == *theVector[i])
            return i;
    return -1;
}

void deleteElement(vector<Picture *> &theVector, const Picture *element) {
    for (int i = 0; i < theVector.size(); ++i) {
        if (element == theVector[i]) {
            theVector.erase(theVector.begin() + i);
            return;
        }
    }
}

struct cmp {
    bool operator()(const Picture *a, const Picture *b) {
        return a->getFValue() > b->getFValue();
    }
};

bool Astart(Picture *&beginPicture, Picture *&endPicture) {
    priority_queue<Picture *, vector<Picture *>, cmp> openQueue;
    vector<Picture *> openTable, closeTable;
    beginPicture->setHValue(*endPicture);
    beginPicture->updateFvalue();
    openQueue.push(beginPicture);
    openTable.push_back(beginPicture);
    int move[4][2] = { {-1, 0},
                      {1,  0},
                      {0,  -1},
                      {0,  1}};
    while (!openQueue.empty()) {
        Picture *bestPicture = openQueue.top();
        if (*bestPicture == *endPicture) {
            delete endPicture;
            endPicture = bestPicture;
            return true;
        }
        closeTable.push_back(bestPicture);
        openQueue.pop();
        deleteElement(openTable, bestPicture);
        //向上下左右四个方向进行拓展
        for (int i = 0; i < 4; ++i) {
            int row = bestPicture->zeroRow + move[i][0];
            int column = bestPicture->zeroColumn + move[i][1];
            if (row >= 0 && row < Picture::rowSize && column >= 0 && column < Picture::columnSize) {
                Picture *successor = new Picture(*bestPicture);
                int **theArray = successor->getPicturePoint();
                theArray[successor->zeroRow][successor->zeroColumn] = theArray[row][column];
                theArray[row][column] = 0;
                successor->zeroRow = row;
                successor->zeroColumn = column;
                successor->parente = bestPicture;
                successor->setGvalue(bestPicture->getGvalue() + 1);
                int flag = inVector(openTable, *successor);
                if (flag >= 0) {
                    if (successor->getGvalue() < openTable[flag]->getGvalue()) {
                        openTable[flag]->setGvalue(successor->getGvalue());
                        openTable[flag]->parente = bestPicture;
                        openTable[flag]->updateFvalue();
                        delete successor;
                    }
                }
                flag = inVector(closeTable, *successor);
                if (flag >= 0) {
                    if (successor->getGvalue() < closeTable[flag]->getGvalue()) {
                        closeTable[flag]->setGvalue(successor->getGvalue());
                        closeTable[flag]->parente = bestPicture;
                        closeTable[flag]->updateFvalue();
                        delete successor;
                        openQueue.push(closeTable[flag]);
                        openTable.push_back(closeTable[flag]);
                        closeTable.erase(closeTable.begin() + flag);
                    }
                } else {
                    successor->setHValue(*endPicture);
                    successor->updateFvalue();
                    openQueue.push(successor);
                    openTable.push_back(successor);
                }
            }
        }
    }
    return false;
}

int Picture::rowSize = 0;
int Picture::columnSize = 0;

void showResult(const Picture *endPicture) {
    if (endPicture != NULL) {
        showResult(endPicture->parente);
        endPicture->showPicture();
    }
}

int main() {
    int rowSize = 0, columnSize = 0;
    cout << "Please input the size of the Picture" << endl;
    cout << "Input the size of row" << endl;
    cin >> rowSize;
    cout << "Input the size of column" << endl;
    cin >> columnSize;
    Picture::setSize(rowSize, columnSize);
    cout << "Please input the begin Picture" << endl;
    Picture *beginPicture = new Picture();
    cout << "Please input the end Picture" << endl;
    Picture *endPicture = new Picture();
    if (Astart(beginPicture, endPicture)) {
        cout<<"The Route is as following"<<endl;
        showResult(endPicture);
        cout << "All steps is " << endPicture->getGvalue() << endl;
    } else{
        cout<<"This A start algorithm can not find the answer"<<endl;
    }

}

博客原文:https://blog.yinaoxiong.cn/2018/05/11/%E5%A4%9A%E6%95%B0%E7%A0%81%E9%97%AE%E9%A2%98%E7%9A%84A%E6%98%9F%E7%AE%97%E6%B3%95.html

include using namespace std; struct node{ int nodesun[4][4]; int pre; //上一步在队列中的位置 int flag ; //步数标识,表示当前的步数为有效的 int value; //目标的差距 int x,y; //空格坐标 }queue[1000]; //移动方向数组 int zx[4]={-1,0,1,0}; int zy[4]={0,-1,0,1}; //当前步数 int top; int desti[4][4];//目标状态 int detect(struct node *p)//检查是否找到 {int i,j; for(i=1;i<4;i++) for(j=1;jnodesun[i][j]!=desti[i][j]) return 0; return 1; } //打印 void printlj() {int tempt; int i,j; tempt=top; while(tempt!=0) { for(i=1;i<4;i++) for(j=1;j<4;j++) {cout<<queue[tempt].nodesun[i][j]; if(j==3) cout<<" "<<endl; } tempt=queue[tempt].pre; } } //现在状态目标状态有多少个不同位置 int VALUE(struct node *p) {int count=0; int i,j; for(i=1;i<4;i++) for(j=1;jnodesun[i][j]!=desti[i][j]) count++; return count; } void main() { //初始化 int i,j,m,n,f; int min=10; int temp,find=0,minnumber; top=1; for(i=1;i<4;i++) for(j=1;j<4;j++) {cout<<"请输入第"<<i<<"行"<<"第"<<j<<"列的值"<>temp; queue[1].nodesun[i][j]=temp; } cout<<"请输入初始状态的空格的位置(行)"<>temp; queue[1].x=temp; cout<<"请输入初始状态的空格的位置(列)"<>temp; queue[1].y=temp; queue[1].value=VALUE(&queue[1]); queue[1].pre=0; //上一步在队列中的位置 queue[1].flag=0; //目标状态 for(i=1;i<4;i++) for(j=1;j<4;j++) {cout<<"请输入目标状态第"<<i<<"行"<<"第"<<j<<"列的值"<>temp; desti[i][j]=temp; } //根据估价函数 while(!find&&top>0) { for(i=1;i<=top;i++) //////////////////////////////////////////// //min为上一图中目标图有多少个元素不相同,queue[i]为当前图目标图有多少个元素不相同通过这两个数的比较,就可以得出当前图较之上一图向目标图接近同时把当前的i记录下来进行下一步比较 {if(queue[i].value<min&&queue[i].flag==0) {minnumber=i;// min=queue[i].value; //还有多少不同的位数 } } queue[minnumber].flag=1; //表示此位有效 ////////////////////////////////////// // for(f=0;f=1&&i=1&&j<=3) {top++; ///////////////////////////////////////////// //位置交换 queue[top]=queue[minnumber]; queue[top].nodesun[m][n]=queue[minnumber].nodesun[i][j]; queue[top].nodesun[i][j]=0; /////////////////////////////////////// //空格移动方向 queue[top].x=i; queue[top].y=j; /////////////////////////////////////// queue[top].pre=minnumber; //上一步在队列中的位置 queue[top].value=VALUE(&queue[top]); //有多少位目标不同 queue[top].flag=0; //标识位初始化 if(detect(&queue[top])) //检查是否为目标 {printlj(); //打印 find=1; //设找到标识位 break; } } } } }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值