人工智能——搜索算法

这篇博客介绍了如何使用DFS、Dijkstra(最小堆优化)和A*算法解决罗马尼亚度假问题,找到从Arad到Bucharest的最短路径。实验结果显示,三种算法都能找到一条路径,其中Dijkstra和A*算法得到相同的最短路径长度为418。

人工智能——搜索算法

实验题目

  • 求解罗马尼亚度假问题,找到从Arad到Bucharest的一条路径
  • 实现两种搜索算法求解该问题
  • 罗马尼亚问题的状态空间图如下

在这里插入图片描述

实验语言和算法

实验语言:C/C++
算法: D f s     D i j k s t r a Dfs\ \ \ Dijkstra Dfs   Dijkstra(最小堆优化) A ∗ ( D i j k s t r a 优 化 ) A^*(Dijkstra优化) A(Dijkstra)

实验算法

1. D F S DFS DFS算法

1. 算法思路:
  1. 利用邻接表存储地图信息
  2. 从起始点s开始,利用邻接表开始寻找与起始点相连的点v,并标记vis[s],防止重复搜索
  3. 将v作为新的当前起始点,进入下一层搜索进行
  4. 取消步骤2中标记,寻找下一个与当前起点相连的结点,重复步骤2-3
  5. 该递归程序边界为:当遍历到终点d,进行输出 s 0 − > d s0->d s0>d的步骤,或者遍历完所有的相连结点,发现均已被访问,则满足两者之一则进行回溯步骤
  6. 算法结束
2. 算法分析
  • 时间复杂度 : O ( b n ) O(b^n) O(bn),其中 b b b为深度因子, n n n为宽度因子
  • 空间复杂度: O ( b n ) O(bn) O(bn)

2. Dijkstra最小堆优化

1. 算法思路:
  1. D i j k s t r a Dijkstra Dijkstra算法采用贪心策略,初始时声明一个 a n s ans ans数组来存储从起点 s s s到各个终点的最短路径长度。
  2. 初始时, a n s [ s ] = 0 ans[s]=0 ans[s]=0,并声明一个 p r i o r i t y _ q u e u e priority\_queue priority_queue来求当前队列中距离起点最短的路径进行出队列来进行访问,初始 p r i o r i t y _ q u e u e priority\_queue priority_queue加入起点 a n s [ s ] = 0 ans[s]=0 ans[s]=0
  3. 当该优先队列非空,将当前距离起点最小的顶点fr出队,并标记其访问,依次遍历其相连的顶点 i i i,若其顶点 i i i当前最短路径 a n s [ i ] > ( a n s [ f r ] ans[i]>(ans[fr] ans[i]>(ans[fr]+ f r fr fr i i i),则更新当前顶点最短路径,并且若 i i i未被加入到优先队列,则将其加入到优先队列中。
  4. 优先队列空,循环结束。
2. 算法分析
  • 时间复杂度: O ( ( n + m ) l o g n ) O((n+m)logn) O((n+m)logn),其中 n n n为定点数, m m m为边数

3. A* 算法

1. 算法思想
  1. d i j s k t r a dijsktra dijsktra的基础上从起点到达当前结点的代价 g ( n ) g(n) g(n)上增加加了一个从当前结点到达终点的代价 h ( n ) h(n) h(n),即总代价 f ( n ) f(n) f(n)

f ( n ) = g ( n ) + h ( n ) f(n)=g(n)+h(n) f(n)=g(n)+h(n)

  1. 即在 d i j k s t r a dijkstra dijkstra算法上,将 p r i o r i t y _ q u e u e priority\_queue priority_queue维护的 g m i n ( n ) g_{min}(n) gmin(n)变为总代价 f m i n ( n ) f_{min}(n) fmin(n),一般的 h ( n ) h(n) h(n)作为启发式规则来估算代价,如可以采用曼哈顿距离、对角距离与欧几里得距离进行估算
2. 算法分析
  1. 若启发函数 h ( n ) h(n) h(n)始终为0,那么此算法便是 D i j k s t r a Dijkstra Dijkstra算法
  2. h ( n ) ≤ h r e a l ( n ) h(n)\le h_{real}(n) h(n)hreal(n),则该算法便一定能找到最短路径
  3. h ( n ) = h r e a l ( n ) h(n)=h_{real}(n) h(n)=hreal(n),则该算法找到最佳路径,且搜索的速度很快
  4. h ( n ) > = h r e a l ( n ) h(n)>=h_{real}(n) h(n)>=hreal(n),则该算法不一定找到最短路径
  5. h ( n ) > > g ( n ) h(n)>>g(n) h(n)>>g(n),则该算法变成了最佳优先搜索

实验结果

  • Dfs算法遍历出所有的路径结果

1:Arad->Sibiu->Fagaras->Bucharest
the path length:450
2:Arad->Sibiu->Rimnicu->Pitesti->Bucharest
the path length:418
3:Arad->Sibiu->Rimnicu->Craiova->Pitesti->Bucharest
the path length:605
4:Arad->Timisoara->Lugoj->Mehadia->Drobeta->Craiova->Pitesti->Bucharest
the path length:733
5:Arad->Timisoara->Lugoj->Mehadia->Drobeta->Craiova->Pitesti->Rimnicu->Sibiu->Fagaras->Bucharest
the path length:1119
6:Arad->Timisoara->Lugoj->Mehadia->Drobeta->Craiova->Rimnicu->Pitesti->Bucharest
the path length:838
7:Arad->Timisoara->Lugoj->Mehadia->Drobeta->Craiova->Rimnicu->Sibiu->Fagaras->Bucharest
the path length:1030
8:Arad->Zerind->Oradea->Sibiu->Fagaras->Bucharest
the path length:607
9:Arad->Zerind->Oradea->Sibiu->Rimnicu->Pitesti->Bucharest
the path length:575
10:Arad->Zerind->Oradea->Sibiu->Rimnicu->Craiova->Pitesti->Bucharest
the path length:762

  • Djikstra+Priority_Queue求最短路结果

Arad->Sibiu->Rimnicu->Pitesti->Bucharest
The shortest length:418

  • A*求最短路结果

Arad->Sibiu->Rimnicu->Pitesti->Bucharest
The shortest length:418

实验代码

#include<bits/stdc++.h>
using namespace std;
const int maxn = 100005;
const int inf = 9999999;
typedef struct edge
{
    int in;
    int v;
    int next;
}edge;
edge e[maxn*2];
typedef struct vex
{
    int first;
    string str;
    int w;
}vex;
typedef struct node
{
    int ww,in;
    bool operator<(const node &a) const
    {
        return a.ww<ww;
    }
}node;

vex v[maxn];
int ans[maxn],res[maxn];
map<string,int> b;
int m,n;bool f,vis[maxn];
void input()
{
    printf("input m and n:\n");
    cin>>m>>n;
    string s,d;int ww;
    for(int i=1;i<=m;i++)
    {
        cin>>s>>ww;
        b[s]=i;
        v[i].str=s;
        v[i].w=ww;
    }
    for(int i=1;i<=n;i++)
    {
        cin>>s>>d>>ww;
        e[i].next=v[b[s]].first;
        e[i].in=b[d];
        e[i].v=ww;
        v[b[s]].first=i;
        int j=i+n;
        swap(s,d);
        e[j].next=v[b[s]].first;
        e[j].in=b[d];
        e[j].v=ww;
        v[b[s]].first=j;
    }
}
int path[maxn],p,ct,pre[maxn];
void output(int p,int anss)
{
    printf("%d:",++ct);
    cout<<v[path[1]].str;
    for(int i=2;i<=p;i++)
        cout<<"->"<<v[path[i]].str;
    printf("\nthe path length:%d\n",anss);
}
void dfs(int s,int d,int anss)
{
    path[++p]=s;
    int p1=p;
    if(s==d) {output(p,anss);return ;}
    for(int i=v[s].first;i!=0;i=e[i].next)
    {
        if(!vis[e[i].in])
        {   
            vis[e[i].in]=true;
            dfs(e[i].in,d,anss+e[i].v);
            //if(f)output(p,anss+e[i].v);
            p=p1;f=false;
            vis[e[i].in]=false;
        }
    }
}
void A(int s,int d)
{
    for(int i=1;i<=m;i++)
    {    
        ans[i]=inf;
        res[i]=inf;
    }
    res[s]=v[s].w;
    ans[s]=0;
    priority_queue<node> Q;
    Q.push(node{0,s});
    while(!Q.empty())
    {
        node fr = Q.top();
        Q.pop();
        int s0=fr.in;
        if(vis[s0]) continue;
        vis[s0]=true;
        for(int i=v[s0].first;i!=0;i=e[i].next)
        {
            if(res[e[i].in]>(e[i].v+ans[s0]+v[e[i].in].w))
            {
                ans[e[i].in]=e[i].v+ans[s0];
                res[e[i].in]=(e[i].v+ans[s0]+v[e[i].in].w);
                pre[e[i].in]=s0;
                if(!vis[e[i].in])
                Q.push(node{res[e[i].in],e[i].in});
            }
        }
    }
}
void dijkstra(int s,int d)
{
    for(int i=1;i<=m;i++)
        ans[i]=inf;
    ans[s]=0;
    priority_queue<node> Q;
    Q.push(node{0,s});
    int mpa=v[s].w;
    while(!Q.empty())
    {
        node fr = Q.top();
        Q.pop();
        int s0=fr.in;
        if(vis[s0]) continue;
        vis[s0]=true;
        for(int i=v[s0].first;i!=0;i=e[i].next)
        {
            if(ans[e[i].in]>(e[i].v+ans[s0]))
            {
                ans[e[i].in]=ans[s0]+e[i].v;
                pre[e[i].in]=s0;
                if(!vis[e[i].in])
                Q.push(node{ans[e[i].in],e[i].in});
            }
        }
    }
}
string str1,str2;
int comand;
void outputs()
{
    int j=b[str2],k=1;
    vector<string> paths(maxn,"\0");
    paths[1]=str2;
    while(j!=b[str1])
    {
        j=pre[j];
        paths[++k]=v[j].str;
    }
    cout<<paths[k];
    k--;
    while(k)
    {
        cout<<"->"<<paths[k];
        k--;
    }
    cout<<"\nThe shortest length:"<<(comand==2?ans[b[str2]]:res[b[str2]]);
}
int main()
{
    input();
    printf("input begin node and final node:\n");
    cin>>str1>>str2;
    printf("1.DFS\n2.Dijkstra\n3.A*\n4.End\n");
    while(1)
    {
        memset(vis,false,sizeof(vis));
        cin>>comand;
        switch(comand)
    {
        case 1:{vis[b[str1]]=true;
        dfs(b[str1],b[str2],0);vis[b[str1]]=false;break;}
        case 2: {dijkstra(b[str1],b[str2]);outputs();break;}
        case 3: {A(b[str1],b[str2]);outputs();break;}
        default:return 0;
    }}
    return 0;
}

实验数据

Expdata

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值