人工智能导论(2)——启发式算法(八数码问题)

实验要求

用A*算法来解决八数码问题。


代码实现

#include<iostream>
#include<stdio.h>
#include<cmath> 
using namespace std;
int open_cnt=0; 
int open_node_cnt;//open表节点个数 
int close_cnt=0;
int noresoult=0;
struct Node{
    int a[3][3];
    int x,y;
    int f,g,h;
    int flag; //上一次移动方向 
    Node *father;
}start,end;
struct Open_Close{
    int f;
    Node *np;
}open[10000],close[10000];
bool isable(){//判断是否有解,逆序数之和奇偶性相同,有解
    int s[9],e[9];
    int tf=0,ef=0;
    int k=0;
        for(int i=0;i<3;i++){
            for(int j=0;j<3;j++){
                s[k]=start.a[i][j];
                e[k]=end.a[i][j];
                k++;
            }
        }

    for(int i=0;i<9;i++){
        for(int j=0;j<i;j++){
            if(s[i]>s[j]&&s[j]!=0) tf+=1;
            if(e[i]>e[j]&&e[j]!=0) ef+=1;
        }
    }
    if((tf%2==1&&ef%2==1)||(tf%2==0&&ef%2==0)) return true;
    else return false;

}
int a_start_h(Node *node){  //求 h() 
    int old_x,old_y,end_x,end_y;
    int h=0;
    for(int k=1;k<9;k++){
        for(int i=0;i<3;i++){
            for(int j=0;j<3;j++){
                if(node->a[i][j]==k){
                    old_x=i;
                    old_y=j;
                }
                if(end.a[i][j]==k){
                    end_x=i;
                    end_y=j;
                }
            }
        }

        h+=abs(old_x-end_x)+abs(old_y-end_y);
    }   

    return h;
}
void input(){               //输入 
    for(int i=0;i<3;i++){
        for(int j=0;j<3;j++){
            cin>>start.a[i][j];
            if(start.a[i][j]==0){
                start.x=i;
                start.y=j;
            }
        }
    }

    for(int i=0;i<3;i++){
        for(int j=0;j<3;j++){
            cin>>end.a[i][j];
            if(end.a[i][j]==0){
                end.x=i;
                end.y=j;
            }
        }
    }
    start.g=0;
    start.h=a_start_h(&start);
    start.f=start.g+start.h;
}
int show(Node *node){               //显示 
    Node *p=node;
    if(p==&start) return 1; 
    else show(p->father);
    cout<<"==============\n";
    for(int i=0;i<3;i++){
        for(int j=0;j<3;j++){
            cout<<p->a[i][j]<<" ";
        }
        printf("\n");
    }
    cout<<"==============\n\n";
}
bool isend(Node *node){         //判断是否为目标节点 
    for(int i=0;i<3;i++){
        for(int j=0;j<3;j++){
            if(node->a[i][j]!=end.a[i][j])
                return false;
        }
    }
    return true;
} 
void sort(Open_Close *open){      //open表排序 
    int min=99999,min_flag=0; 
    Open_Close temp;
    for(int i=0;i<=open_cnt;i++){
        if(min>open[i].f&&open[i].f>0){
            min=open[i].f;
            min_flag=i;
        }
    }
    temp=open[min_flag];
    open[min_flag]=open[0];
    open[0]=temp;   
}
void move(int flag,Node *node){   //向四个方向扩展 
    int temp;
    if(flag==1&&node->x>0){
        Node *n = new Node();
        for(int i=0;i<3;i++){
            for(int j=0;j<3;j++){
                n->a[i][j]=node->a[i][j];
            } 
        }
        n->a[node->x][node->y]=node->a[node->x-1][node->y];
        n->a[node->x-1][node->y]=0; 
        n->x=node->x-1;
        n->y=node->y;
        n->flag=3; 
            n->father=node;
        n->g=node->g+1;             //  求 g() 
        n->h=a_start_h(n);
        n->f=n->g+n->h;
        open_cnt++;
        open_node_cnt++;
        open[open_cnt].np=n;        //添加到open表
        open[open_cnt].f=n->f;  //  求 f() 
    }
    else if(flag==2&&node->y<2){
        Node *n = new Node();
        for(int i=0;i<3;i++){
            for(int j=0;j<3;j++){
                n->a[i][j]=node->a[i][j];
            }
        }
        n->a[node->x][node->y]=node->a[node->x][node->y+1];
        n->a[node->x][node->y+1]=0;
        n->x=node->x;
        n->y=node->y+1;
        n->flag=4; 
            n->father=node;
        n->g=node->g+1;             //  求 g() 
        n->h=a_start_h(n);
        n->f=n->g+n->h;
        open_cnt++;
        open_node_cnt++;
        open[open_cnt].np=n;        //添加到open表
        open[open_cnt].f=n->f;  //  求 f() 
    }
    else if(flag==3&&node->x<2){
        Node *n = new Node();
        for(int i=0;i<3;i++){
            for(int j=0;j<3;j++){
                n->a[i][j]=node->a[i][j];
            }
        }
        n->a[node->x][node->y]=node->a[node->x+1][node->y];
        n->a[node->x+1][node->y]=0; 
        n->x=node->x+1;
        n->y=node->y;   
        n->flag=1; 
            n->father=node;
        n->g=node->g+1;             //  求 g() 
        n->h=a_start_h(n);
        n->f=n->g+n->h;
        open_cnt++;
        open_node_cnt++;
        open[open_cnt].np=n;        //添加到open表
        open[open_cnt].f=n->f;  //  求 f() 
    }
    else if(flag==4&&node->y>0){
        Node *n = new Node();
        for(int i=0;i<3;i++){
            for(int j=0;j<3;j++){
                n->a[i][j]=node->a[i][j];
            }
        }
        n->a[node->x][node->y]=node->a[node->x][node->y-1];
        n->a[node->x][node->y-1]=0;
        n->x=node->x;
        n->y=node->y-1;     
        n->flag=2; 
            n->father=node;
        n->g=node->g+1;             //  求 g() 
        n->h=a_start_h(n);
        n->f=n->g+n->h;
        open_cnt++;
        open_node_cnt++;
        open[open_cnt].np=n;        //添加到open表
        open[open_cnt].f=n->f;  //  求 f() 
    }    


} 
void expand(Node *node){    //节点扩展    
    for(int i=1;i<5;i++){
        if(i!=node->flag) move(i,node);
    }
}
int main(){

    input();
    open[0].np=&start;//start放入open表 
    open_node_cnt=1;

    if(isable()){
        while(true){//open表不为空 
            if(isend(open[0].np)){
                cout<<"\n路径:\n";
                show(open[0].np);
                break;
            } 

            expand(open[0].np);//扩展最优节点的子节点 

            open[0].np=NULL;
            open[0].f=-1;
            open_node_cnt--; 

            sort(open);   //open表排序
        }
    }
    else cout<<"无解";


} 
/*
有解
1 0 3
7 2 4
6 8 5
1 2 3
8 0 4
7 6 5
无解
1 2 3 
4 0 7 
6 5 8
3 2 1 
6 5 0 
4 7 8
*/
  • 0
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值