最短路径问题:对任意给出的图G(V,E)和起点S,终点T,如何求从S到T的最短路径。解决最短路径问题的算法有Dijkstra算法,Bellman-Ford算法,SPFA算法和Floyd算法。
主要用于解决单源最短路径问题,即给定图G(V,E)和起点s,通过算法得到S到达其他每个顶点的最短距离。
算法步骤:设置集合S存放已被访问的顶点,然后执行n次下面的每个步骤(n为顶点个数)
(1)每次从集合V-S(未被访问的顶点)中选择与起点S的最短距离最小的一个顶点记为u,访问并加入集合s
(2)之后,令顶点u为中介点,优化起点S与所有从u可以到达的顶点v之间的最短距离。
集合S可以用一个布尔型数组来实现,当vis[i]==true时表示顶点vi已被访问。
令int型数组d[]表示从起点到任意顶点的最短距离,初始时给起点s的d[s]赋值为0,其余为很大的值,可以用二进制编码的十六进制0x3fffffff来表示inf,即不可到达。
Dijkstra(G,d[],s)
{
初始化;
for(循环n次)
{
u=使d[u]最小的还未被访问过的顶点的标号;
记u已被访问;
for(从u出发能到达的所有顶点v)
{
if(v未被访问&&以u为中介点使s到顶点v的最短距离最优)
{
优化d[v];
}
}
}
}
const int maxn=1000;
const int INF=0x3fffffff;
int n,G[maxn][maxn];
int d[maxn];
bool vis[maxn]={false};
void Dijkstra(int s)
{
fill(d,d+maxn,INF);
d[s]=0;
for(int i=0;i
时间复杂度为O(n^2)
const int INF=0x3fffffff;
const int maxn=10000;
struct node
{
int v;
int dis;
};
vector adj[maxn];
int n;
int d[maxn];
bool vis[maxn]={false};
void Dijkstra(int s)
{
fill(d,d+maxv,INF); //慎用memset
d[s]=0;
for(int i=0;i
时间复杂度同上。这2种做法的时间复杂度都是O(n^2)。由于需要把每条边都标记为已访问,因此外层循环的O(n)无法避免,但是寻找最小d[u]的过程可以不必达到O(n)的复杂度,可以使用堆优化的方式来降低复杂度,最简练的方式是使用优先队列priority_queue来实现。这样时间复杂度将为O(nlogn).
const int maxv=1000;
const int INF=0x3fffffff;
struct node
{
int v,dis;
bool friend operator < (node n1,node n2) //设置优先级,即距离小的优先级高
{
return n1.dis>n2.dis;
}
};
vector adj[maxv];
priority_queue q; //优先队列
bool vis[maxv];
int dis[maxv];
int n,m,s; //点数,边数和 起点下标
void Dij(int s)
{
dis[s]=0; //起点最小距离为0
node now;
now.v=s;
now.dis=0;
q.push(now); //放入起点
while(!q.empty())
{
node topnode=q.top();
q.pop();
if(!vis[topnode.v])
{
vis[topnode.v]=1;
for(int i=0;i
最小堆保证每次取出的都是距离最小的,可能会重复放进队列,但是如果已经访问过就不会再访问。
案例一:
输入:第一行给出3个整数,m,n,t;分别表示m个顶点,n条边,起点为t。接下来n行输入,每行给出边的起点终点和边权。需要输出起点到每个顶点的最短距离。
未改进版:
#include
#include
#include
#include
#include
using namespace std;
struct node
{
int v,dis;
};
const int maxv=1000; //最大顶点数
vector adj[maxv]; //邻接表
int dis[maxv]; //存放最短距离
int n,m,s; //顶点数,边数,起点下标
bool vis[maxv]; //记录是否还没有被访问
const int INF=0x3fffffff;
void Dij(int s)
{
dis[s]=0;
for(int i=0;i
优先队列改进版:
#include
#include
#include
#include
using namespace std;
const int maxv=1000;
const int INF=0x3fffffff;
struct node
{
int v,dis;
bool friend operator < (node n1,node n2) //设置优先级
{
return n1.dis>n2.dis;
}
};
vector adj[maxv];
priority_queue q;
bool vis[maxv];
int dis[maxv];
int n,m,s; //点数,边数和 起点下标
void Dij(int s)
{
dis[s]=0;
node now;
now.v=s;
now.dis=0;
q.push(now);
while(!q.empty())
{
node topnode=q.top();
q.pop();
if(!vis[topnode.v])
{
vis[topnode.v]=1;
for(int i=0;i