人工智能——搜索算法
实验题目
- 求解罗马尼亚度假问题,找到从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. 算法思路:
- 利用邻接表存储地图信息
- 从起始点s开始,利用邻接表开始寻找与起始点相连的点v,并标记vis[s],防止重复搜索
- 将v作为新的当前起始点,进入下一层搜索进行
- 取消步骤2中标记,寻找下一个与当前起点相连的结点,重复步骤2-3
- 该递归程序边界为:当遍历到终点d,进行输出 s 0 − > d s0->d s0−>d的步骤,或者遍历完所有的相连结点,发现均已被访问,则满足两者之一则进行回溯步骤
- 算法结束
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. 算法思路:
- D i j k s t r a Dijkstra Dijkstra算法采用贪心策略,初始时声明一个 a n s ans ans数组来存储从起点 s s s到各个终点的最短路径长度。
- 初始时, 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。
- 当该优先队列非空,将当前距离起点最小的顶点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未被加入到优先队列,则将其加入到优先队列中。
- 优先队列空,循环结束。
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. 算法思想
- 在 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)
- 即在 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. 算法分析
- 若启发函数 h ( n ) h(n) h(n)始终为0,那么此算法便是 D i j k s t r a Dijkstra Dijkstra算法
- 若 h ( n ) ≤ h r e a l ( n ) h(n)\le h_{real}(n) h(n)≤hreal(n),则该算法便一定能找到最短路径
- 若 h ( n ) = h r e a l ( n ) h(n)=h_{real}(n) h(n)=hreal(n),则该算法找到最佳路径,且搜索的速度很快
- 若 h ( n ) > = h r e a l ( n ) h(n)>=h_{real}(n) h(n)>=hreal(n),则该算法不一定找到最短路径
- 若 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;
}

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

被折叠的 条评论
为什么被折叠?



