zoukankan      html  css  js  c++  java
  • 基于图搜索技术的八数码问题求解C++

    八数码,在3×3的方格棋盘上,摆放着1到8这八个数码,有1个方格是空的,其初始状态如图1所示,
    要求对空格执行空格左移、空格右移、空格上移和空格下移这四个操作使得棋盘从初始状态到目标状态。

    内容提要:
    分别用广度优先搜索策略、深度优先搜索策略和启发式搜索算法(至少两种)求解八数码问题;
    分析估价函数对启发式搜索算法的影响;探究讨论各个搜索算法的特点。

    #include<bits/stdc++.h> 
    using namespace std;
    #define endl "
    " 
    const int INF=0x3f3f3f3f;
    struct Status{
        int gx; //实际已走代价 
        int fx; //估值    
        string sta;   //长度为9的字符串表示状态 
        bool operator < (const Status& t) const{
            return fx > t.fx;
        }
    }initial,target;
    unordered_map<string,int>close; //记录已遍历的状态 
    const int LAYER_MAX=20;         //dfs最大深度 
    int MAX_COST=0;                //遍历到目标状态的代价
    int dir[4][2]={{-1,0},{1,0},{0,-1},{0,1}}; //下一状态可能的改变 
    //输出显示当前状态 
    void show(const Status& t){
        cout<<"当前状态gx="<<t.gx<<" fx="<<t.fx<<endl; 
        for(int i=0;i<3;i++){
            for(int j=0;j<3;j++){
                cout<<t.sta[i*3+j];
            }
            cout<<endl;
        }
    }
    //计算估值函数 
    int get_hx(const Status& t){
        int hx=0;
        for(int i=0;i<9;i++)
            if(target.sta[i]!=t.sta[i])  //计算位置不同的个数 
                hx++;
        return hx;
    }
    void init(){
        // 初始状态
        cout<<"请输入初始状态:"<<endl;
        initial.sta="";
        initial.gx=0;
        initial.fx=get_hx(initial)+initial.gx;
        vector<int>used(10,0);
        for(int i=0;i<9;i++){
            int index=0;
            while(1){
                index=rand()%9;
                if(!used[index])break;
            }
            if(index==0)initial.sta+=' ';
            else initial.sta+=char('0'+index);
            used[index]=1;
        }
        for(int i=0;i<3;i++){
            for(int j=0;j<3;j++){
                cout<<initial.sta[i*3+j];
            }
            cout<<endl;
        }
        //cout<<"请输入目标状态:"<<endl;
        target.sta="1238 4765";
        target.gx=INF;
        target.fx=INF;
    } 
    int bfs(){
        close.clear();
        queue<string>open;
        open.push(initial.sta);
        close[initial.sta]=0;
        while(!open.empty()){
            string now=open.front();
            open.pop();
            //show(now);
            if(now==target.sta){
                return close[target.sta]; //到达目标状态 
            }
            int dis=close[now];
            int index;
            for(int i=0;i<9;i++){
                if(now[i]==' '){
                    index=i;
                    break;
                }
            }
            int row=index/3,colum=index%3;  //一维坐标转化成二维 
            for(int i=0;i<4;i++){
                int trow=row+dir[i][0]; //假设空白处移动 
                int tcolum=colum+dir[i][1]; 
                if(trow>=0&&trow<=2&&tcolum>=0&&tcolum<=2){ //判断移动后的坐标是否合理 
                    string next=now;
                    swap(next[trow*3+tcolum],next[index]);  //真实移动空白处 
                    if(!close.count(next)){ //判断当前状态是否遍历过 
                        close[next]=dis+1;
                        open.push(next);
                        MAX_COST++;
                    }
                }
            }
        }
        return -1;
    }
    void dfs(string now,int row,int colum,int layer_num){
        if(!close.count(now)) close[now]=layer_num;      //贪心获取较小的可行解 
        else {
            if(close[now]<layer_num) return ;
            else close[now]=layer_num;
        }
        if(layer_num>=LAYER_MAX){  //超过搜索层数 
            return ;
        }
        if(now==target.sta){  //达到目标状态 
            return ;
        }
        //往上下左右四个方向进行扩展 
        for(int i=0;i<4;i++){
            int trow=row+dir[i][0];
            int tcolum=colum+dir[i][1];
            if(trow>=0&&trow<=2&&tcolum>=0&&tcolum<=2){ //选择合理状态 
                swap(now[trow*3+tcolum],now[row*3+colum]);
                dfs(now,trow,tcolum,layer_num+1);
                MAX_COST++;
                swap(now[trow*3+tcolum],now[row*3+colum]);
            }
        }
    } 
    
    void astar(){
        close.clear();
        close[target.sta]=INF;
        priority_queue<Status>open;
        open.push(initial);
        while(!open.empty()){
            Status now=open.top();
            open.pop();
            close[now.sta]=now.fx;
            //show(now);   //输出当前状态 
            if(!get_hx(now))break; //到达目标状态 
            //找到空白处坐标 
            int row,colum; 
            for(int i=0;i<9;i++){
                if(now.sta[i]==' '){
                    row=i/3; colum=i%3;  //一维坐标转化成二维 
                    break;
                }
            }
            for(int i=0;i<4;i++){
                //假设空白处移动 
                int trow=row+dir[i][0];
                int tcolum=colum+dir[i][1];
                //判断移动后的坐标是否合理 
                if(trow>=0&&trow<=2&&tcolum>=0&&tcolum<=2){
                    Status next=now;
                    next.gx++;
                    next.fx=next.gx+get_hx(next);
                    //真实移动空白处 
                    swap(next.sta[trow*3+tcolum],next.sta[row*3+colum]);
                    //启发判断下一状态 
                    if(!close.count(next.sta)||close[next.sta]>=next.fx){
                        open.push(next);
                        MAX_COST++;
                    }
                }
            }
            
        } 
    }
    int main(){
        
        srand(time(NULL)); //时间种子 
        init();
        int x,y;  //获取初始状态的空格位置 
        for(int i=0;i<3;i++){
            for(int j=0;j<3;j++){
                if(initial.sta[i*3+j]==' '){
                    x=i;
                    y=j;
                    break;
                 }
            }
         }
        cout<<"广度优先搜索bfs算法:"<<endl; 
        int ans=bfs(); 
        cout<<"到目标状态广搜代价:"<<MAX_COST<<endl;
        cout<<"到目标状态最小代价:";
        cout<<(ans==-1?"不可解":to_string(ans))<<endl;
         //进到深度搜索 
        cout<<"深度优先搜索dfs算法:"<<endl;
        close.clear();        //初始化close表 
        close[target.sta]=INF;
        MAX_COST=0;
        dfs(initial.sta,x,y,0);
        cout<<"到目标状态深搜代价:"<<MAX_COST<<endl;   
        cout<<"到目标状态最小代价:";
        cout<<(close[target.sta]==INF?"不可解":to_string(close[target.sta]))<<endl; 
        //进到启发式搜索 
        cout<<"启发搜索A*算法:"<<endl;
        MAX_COST=0; 
        astar();
        cout<<"到目标状态广搜代价:"<<MAX_COST<<endl;
        cout<<"到目标状态最小代价:";
        cout<<(close[target.sta]==INF?"不可解":to_string(close[target.sta]))<<endl;
        return 0;
    } 
    
    
    
  • 相关阅读:
    centos7 安装高版本svn
    idea 常用快捷键
    IDEA 打可执行jar包(maven项目)
    服务器安装JDK
    阿里云服务器连接AWS-S3
    mysql5.7 修改密码,修改权限
    win10 手动安装mysql-8.0.11-winx64.zip
    centos7 关闭防火墙
    centos7 配置阿里云yum源
    centos7 源码安装nginx
  • 原文地址:https://www.cnblogs.com/hrdate/p/15481380.html
Copyright © 2011-2022 走看看