启发式算法-A*算法

A*(A-Star)算法是一种静态路网中求解最短路径最有效的直接搜索方法
A算法公式表示为: f(n)=g(n)+h(n)
其中

  • f(n) 是从初始点经由节点n到目标点的估价函数
  • g(n) 是在状态空间中从初始节点到n节点的实际代价
  • h(n) 是从n到目标节点最佳路径的估计代价

启发信息给得越多(估价函数值越大),则A算法需要搜索处理的状态数就越少,效率就越高。但并不是估计值越大越好,有时估价函数值太大会使A算法不一定搜索到最优解。

此时可引入A*算法公式:f*(n) = g* (n) + h* (n)
其中

  • g* (n)是从初始结点到n结点的最短路径代价
  • h* (n)是从n结点到目的结点的最佳路径代价

当我们要求估价函数f(n)中的h(n)都小于等于h*(n)即: h(n) <=h*(n)时 A搜索算法就成为A*搜索算法,所得路径为最优路径。

如某一问题有解,那么利用A*搜索算法对该问题进行搜索则一定能搜索到解,并且一定能搜索到最优的解而结束!

A*例题

问题分析:从节点A开始搜索至#节点,该节点对应的h* (n)即为该城市到目标城市的直线距离(即最佳路径代价),从A点到#节点走过的实际距离(即最短路径代价)则为g* (n)。每次搜索节点查找最小的g* (n) + h* (n)。

#include<stdio.h>
#include<stdio.h>
#include<stdlib.h>
#include<string>
int city_num=0;//城市数目
int g[100][100];//存储城市间实际距离的邻接矩阵

int closeNum=0;//close表大小
int track[100];//行驶路径
int tra_num=0;//途径城市的数目
typedef struct node//代表城市的结构体
  { int data; //城市名
    int num;//估价函数值
     struct node *next; //存储下一个结点的地址
     int fa;//上一个城市
  }LinkList;
typedef struct distance
  { 
      char city;
      int dist;
  }dis;//存储实际距离和数字与城市名的对应关系
dis h[100];
LinkList *head,*p,*q;
void INITLIST(LinkList *L){
 // L=(LinkList*)malloc(sizeof(LinkList));
  //判断是否申请成功
  if(!L){
     printf("无内存空间可分配");exit(0);}
  L->next=NULL;
} //INITLIST      
LinkList close[100];//close表
void Init()//初始化,主要是将文件中的内容读入
{
    FILE *stream=fopen("text.txt","r");
    int initNum=0;//城市数目
    if(stream==NULL)
    printf("The file fscanf.out was not opened
");
    else
    {
        while(fscanf(stream,"%d%c",&h[initNum].dist,&h[initNum].city) !=EOF){//h数组存储各城市到达目标城市的直线距离
            initNum++;
        }
        city_num=initNum;
     fclose(stream);
    }
    FILE *stream2=fopen("map.txt","r");
    //int initNum=0;
    if(stream2==NULL)
    printf("The file fscanf.out was not opened
");
    else
    {
        for(int i=0;i<initNum;i++){
            for(int j=0;j<initNum;j++){
                if(fscanf(stream,"%d",&g[i][j]) !=EOF)
                    //initNum++;
                        continue;
            }
        }
     fclose(stream);
    }
}
int Initend()//仅仅是为了找到目标城市而已
{
    for(int i=0;i<city_num;i++){
        if(h[i].dist==0)
            return i;
    }
    return -1;
}
int find(char c){
    for(int i=0;i<city_num;i++){
        if(h[i].city==c)
            return i;
    }
    return -1;
}
void addOpen(LinkList *p,int a,int dis,int f)//将走过的节点加入到open表
{
    LinkList *q;
    //p =(LinkList *)malloc(sizeof(LinkList));
//  q =(LinkList *)malloc(sizeof(LinkList));
    q=head;
    p->data=a;
    p->fa=f;
    p->num=dis+h[a].dist;
    while(1){
        if(q->next==NULL||q->next->num>p->num){
            p->next=q->next;
            q->next=p;
            return;
        }
        q=q->next;
    }
}
void deleteOpen(int n)//将重新找到更短的路径从open表替换
{
    LinkList *r;
    r=head;
    while(r->next!=NULL){
        if(r->next->data==n){
            r->next=r->next->next;
            return;
        }
        else
        {
            r=r->next;
        }
    }
    return;
}
int findClose(int a)//查找某城市是否在close表中
{
    for(int i=0;i<city_num;i++){
        if(close[i].data==a)
            return i;
    }
    return -1;
}

void deleteclose(int n)//在需要时从close表中转移出来
{
    for(int i=0;i<closeNum;i++){
        if(close[i].data==n){
            close[i].data=close[closeNum-1].data;
            close[i].num=close[closeNum-1].num;
            closeNum--;
            return;
        }

    }
    return;
}
int findOpen(int n,int dis)//查找某节点是否在open表中
{
    LinkList *r;
    r=head;
    int i=0;
    while(r->next!=NULL){
        if(r->next->data==n){
            if(r->next->num>dis+h[n].dist)
                return 1;
            else
                return 0;
        }   
        else
        {
            r=r->next;
            i++;
        }
    }
    return -1;
}
void Track()//形成track表
{
    int a,b;
    track[tra_num++]=head->next->data;
    b=head->next->fa;
    track[tra_num++]=b;
    while(1){
        for(int i=0;i<closeNum;i++){
            if(close[i].data==b){
                if(close[i].fa==-1)
                    return;
                b=close[i].fa;
                track[tra_num++]=b;
                break;
            }
        }

    }
}
int main(){
    Init();
    char name;
    int end;
    printf("输入初始城市:");
    scanf("%c",&name);
    end=Initend();//找到目标城市
    head =(LinkList *)malloc(sizeof(LinkList));
    INITLIST(head);//初始化open表

    p =(LinkList *)malloc(sizeof(LinkList));//...
    p->next=head->next;
    head->next=p;
    p->num=h[find(name)].dist;
    p->data=find(name);
    p->fa=-1;//...起点城市入open表
    LinkList *t;
    while(head->next->data!=end){
        t=head->next;
        //addTrack(t);
        head->next=t->next;//open表头入closeclose[closeNum].data=t->data;
        close[closeNum].num=t->num;
        close[closeNum++].fa=t->fa;
        //printf("%d
",t->data);
        for(int i=0;i<city_num;i++){
            if(g[t->data][i]!=0){//如果找到与此城市相连的城市&&不在close表中
                p =(LinkList *)malloc(sizeof(LinkList));
                if(findClose(i)==-1&&findOpen(i,t->num-h[t->data].dist+g[t->data][i])==-1){
                    addOpen(p,i,t->num-h[t->data].dist+g[t->data][i],t->data);//添加到open表中(城市序号,到此城市要走的路)

                }
                if(findOpen(i,t->num-h[t->data].dist+g[t->data][i])==1){
                    deleteOpen(i);
                    addOpen(p,i,t->num-h[t->data].dist+g[t->data][i],t->data);
                }
                if(findClose(i)!=-1){
                    if(close[findClose(i)].num>t->num-h[t->data].dist+g[t->data][i]+h[t->data].dist){
                        deleteclose(i);
                        addOpen(p,i,t->num-h[t->data].dist+g[t->data][i],t->data);
                    }
                }

            }
    //      close[closeNum].data=t->data;
    //      close[closeNum].next=NULL;
    //      close[closeNum].num=t->num;
    //      closeNum++;
        }
    }
    Track();
    printf("最优路径为:");
    for(int i=tra_num-1;i>=0;i--){
        printf("%c  ",h[track[i]].city);
    }
    printf("
");

    return 0;
}

结果截图

原文地址:https://www.cnblogs.com/leishitou/p/5436195.html