算法笔记:
1) Dijkstra 算法的伪代码:
/**
1) Dijkstra 算法的伪代码:
void Dijkstra(G,d[],s)
{
初始化:
for(循环 n 次)
{
u=使d[u] 最小的还未被访问的顶点的标号;
记u为已被访问;
for(从u 出发能达到的所有顶点)
{
if(v未被访问 && 以u为中介点使s到达v能使d[v]更优)
优化d[v];
}
}
}
*/
2) Dijkstra 算法的邻接矩阵实现:
时间复杂度:O(V*(V+V) = O(V^2);
/**
2) Dijkstra 算法的邻接矩阵实现:
时间复杂度:O(V*(V+V) = O(V^2);
const int maxn = 1010;
const int INF = 0x3fffffff;
int Nv,G[maxn][maxn]; //Nv 是顶点数 ,G是邻接矩阵;
int d[maxn]; //起点到达终点的最短路径长度
bool hs[maxn] = {false};
void Dijkstra(int s)
{
fill(d,d+maxn,INF); //初始化数组d;
d[s] = 0; // 起点到达终点的距离;
for(int i=0;i<Nv;++i)
{
int u=-1,MIN=INF;
for(int j=0;j<Nv;++j)
{
if(hs[j]==false && d[j] < MIN)
{
u=j;
MIN=d[j];
}
}
if(u==-1)
return;
hs[u]=true;
for(int v=0;v<Nv;++v)
{
if(hs[v]==false && G[u][v]!=INF && d[u]+G[u][v] < d[v] )
d[v] = d[u] + G[u][v];
}
}
}
*/
3) Dijkstra 算法的邻接表实现:
时间复杂度:O(V^2 + E);
/**
3) Dijkstra 算法的邻接表实现:
时间复杂度:O(V^2 + E);
struct GNode
{
int v, dis; //v 为边的目标顶点,dis为边权
}
const int maxn = 1010;
const int INF = 0x3fffffff;
int Nv; //Nv 是顶点数 ,G是邻接矩阵;
vector<Node> Adj[maxn]; //邻接表
int d[maxn]; //起点到达终点的最短路径长度
bool hs[maxn] = {false}; //标记数组
void Dijkstra(int s)
{
fill(d,d+maxn,INF); //初始化数组d;
d[s] = 0; // 起点到达终点的距离;
for(int i=0;i<Nv;++i)
{
int u=-1,MIN=INF;
for(int j=0;j<Nv;++j)
{
if(hs[j]==false && d[j] < MIN)
{
u=j;
MIN=d[j];
}
}
if(u==-1)
return;
hs[u]=true;
for(int v=0;v<Adj[u].size();++v)
{
if(hs[v]==false && d[u]+Adj[u][v].dis < d[v] )
d[v] = d[u] + Adj[u][v].dis;
}
}
}
*/
4) Dijkstra 算法的邻接矩阵实现:
时间复杂度:O(V*(V+V) = O(V^2);如果要找出一条最短路径,并打印出这条路径该走的顶点编号,那么可以用一个 pre[maxn] 数组来存储;
只需要在(2) 的基础上添加两个语句便可;
/**
4) Dijkstra 算法的邻接矩阵实现:
时间复杂度:O(V*(V+V) = O(V^2);
如果要找出一条最短路径,并打印出这条路径该走的顶点编号,那么可以用一个 pre[maxn] 数组来存储;
只需要在(2) 的基础上添加两个语句便可;
const int maxn = 1010;
const int INF = 0x3fffffff;
int Nv,G[maxn][maxn]; //Nv 是顶点数 ,G是邻接矩阵;
int d[maxn]; //起点到达终点的最短路径长度
int pre[maxn]; //pre[v]表示从起点到v的路径上前驱顶点的编号; (新添加)
bool hs[maxn] = {false};
void Dijkstra(int s)
{
fill(d,d+maxn,INF); //初始化数组d;
memset(pre,-1,sizeof(pre) ); // 初始化pre数组;(新添加)
d[s] = 0; // 起点到达终点的距离;
for(int i=0;i<Nv;++i)
{
int u=-1,MIN=INF;
for(int j=0;j<Nv;++j)
{
if(hs[j]==false && d[j] < MIN)
{
u=j;
MIN=d[j];
}
}
if(u==-1)
return;
hs[u]=true;
for(int v=0;v<Nv;++v)
{
if(hs[v]==false && G[u][v]!=INF && d[u]+G[u][v] < d[v] )
{
d[v] = d[u] + G[u][v];
pre[v]=u; // 记录v的前驱顶点是 u; (新添加)
}
}
}
}
如果要得到起点到终点的路径:那么我们只需要从终点开始递归,每次函数内的递归参数传入pre[u] 的值即可;
至于递归边界和递归式是什么:
递归边界:pre[v] 的值是-1 的时候就到达了起点:
递归式 :dfs(pre[v]);
因此我们能得到递归函数:
void dfs(int u)
{
if(pre[u] < -1 ) // 或者写为 if(u == st)
{
printf("%d\n",u);
return;
}
else
{
dfs(pre[u]);
printf("%d\n",u);
}
}
*/
5) 在找出起点到终点的距离最近的同时,也要使得起点到终点的边的权值之和最小,
假定新增了边的权值(不只是距离);Dijkstra 算法的邻接矩阵实现:
时间复杂度:O(V*(V+V) = O(V^2);
/**
5) 在找出起点到终点的距离最近的同时,也要使得起点到终点的边的权值之和最小,
假定新增了边的权值(不只是距离);
Dijkstra 算法的邻接矩阵实现:
时间复杂度:O(V*(V+V) = O(V^2);
const int maxn = 1010;
const int INF = 0x3fffffff;
int Nv,G[maxn][maxn]; //Nv 是顶点数 ,G是邻接矩阵;
int d[maxn]; //起点到达终点的最短路径长度
int c[maxn]; // 起点到终点的最小消耗(花费);
bool hs[maxn] = {false}; //顶点是否被选择;
void Dijkstra(int s)
{
fill(d,d+maxn,INF); //初始化数组d;
d[s] = 0; // 起点到达终点的距离;
fill(c,c+maxn,INF); //求最小花费的时候,还是最好把花费数组初始化为INF;
c[st] = 0; // 起点的花费为0
for(int i=0;i<Nv;++i)
{
int u=-1,MIN=INF;
for(int j=0;j<Nv;++j)
{
if(hs[j]==false && d[j] < MIN)
{
u=j;
MIN=d[j];
}
}
if(u==-1)
return;
hs[u]=true;
for(int v=0;v<Nv;++v)
{
if(hs[v]==false && G[u][v]!=INF)
{
if(d[u]+G[u][v] < d[v] )
{
d[v] = d[u] + G[u][v];
c[v] = c[u] + cost[u][v];
}
else if( d[u]+G[u][v] == d[v] && c[u] + cost[u][v] < c[v])
c[v] = c[u] + cost[u][v];
}
}
}
}
*/
6) 在找出起点到终点的距离最近的同时,也要使得起点到终点的点的权值之和最大,
假定新增了顶点的权值;Dijkstra 算法的邻接矩阵实现:
时间复杂度:O(V*(V+V) = O(V^2);
/**
6) 在找出起点到终点的距离最近的同时,也要使得起点到终点的点的权值之和最大,
假定新增了顶点的权值;
Dijkstra 算法的邻接矩阵实现:
时间复杂度:O(V*(V+V) = O(V^2);
const int maxn = 1010;
const int INF = 0x3fffffff;
int Nv,G[maxn][maxn]; //Nv 是顶点数 ,G是邻接矩阵;
int weight[maxn]; //顶点的权值;
int d[maxn]; //起点到达终点的最短路径长度
int w[maxn]; // 起点到终点的最大筹集物资;
bool hs[maxn] = {false}; //顶点是否被选择;
void Dijkstra(int s)
{
fill(d,d+maxn,INF); //初始化数组d;
d[s] = 0; // 起点到达终点的距离;
w[s] = weight[s];
for(int i=0;i<Nv;++i)
{
int u=-1,MIN=INF;
for(int j=0;j<Nv;++j)
{
if(hs[j]==false && d[j] < MIN)
{
u=j;
MIN=d[j];
}
}
if(u==-1)
return;
hs[u]=true;
for(int v=0;v<Nv;++v)
{
if(hs[v]==false && G[u][v]!=INF)
{
if(d[u]+G[u][v] < d[v] )
{
d[v] = d[u] + G[u][v];
w[v] = w[u] + weight[v];
}
else if( d[u]+G[u][v] == d[v] && w[u] + weight[v] > w[v]) //最短距离相同时看是否能使w[v]更优
w[v] = w[u] + weight[v];
}
}
}
}
*/
7) 在找出起点到终点的距离最近的同时,要求出最短路径条数;
Dijkstra 算法的邻接矩阵实现:
时间复杂度:O(V*(V+V) = O(V^2);
/**
7) 在找出起点到终点的距离最近的同时,要求出最短路径条数;
Dijkstra 算法的邻接矩阵实现:
时间复杂度:O(V*(V+V) = O(V^2);
const int maxn = 1010;
const int INF = 0x3fffffff;
int Nv,G[maxn][maxn]; //Nv 是顶点数 ,G是邻接矩阵;
int d[maxn]; //起点到达终点的最短路径长度
int num[maxn]; // 最短路径条数
bool hs[maxn] = {false}; //顶点是否被选择;
void Dijkstra(int s)
{
fill(d,d+maxn,INF); //初始化数组d;
d[s] = 0; // 起点到达终点的距离;
num[s] = 1;
for(int i=0;i<Nv;++i)
{
int u=-1,MIN=INF;
for(int j=0;j<Nv;++j)
{
if(hs[j]==false && d[j] < MIN)
{
u=j;
MIN=d[j];
}
}
if(u==-1)
return;
hs[u]=true;
for(int v=0;v<Nv;++v)
{
if(hs[v]==false && G[u][v]!=INF)
{
if(d[u]+G[u][v] < d[v] )
{
d[v] = d[u] + G[u][v];
num[v] = num[u];
}
else if( d[u]+G[u][v] == d[v] ) //最短距离相同时num[u] 与 num[v] 叠加
num[v]+=num[u];
}
}
}
}
*/