版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/srping123/article/details/83538878
1. dijkstra算法
总体思路是使用一个距离数组来存储到源点的最小距离,每次找到距离数组中最小的那个点对应的距离和点,遍历这个点的邻接点,如果用这个点做跳板,距离更小的话,更新邻接点对应的距离数组。
int * dijkstra(int s, ALGraph & graph){
for(int i=0;i<graph.vexNum;i++){
visited[i]=-1;
}
int distance[graph.vexNum];
fill(distance.begin(),distance.end(),INF);
distance[s]=0;
for(int i=0;i<graph.vexNum;i++){
int u=-1;
int min=INF;
for(int j=0;j<graph.vexNum;j++){
if(visited[j]==-1 && min>distance[j]){
u=j;
min=distance[j];
}
}
if(u==-1){
break;
}
visited[u]=1;
ArcNode * firstarc=graph.adjList[u].firstarc;
while(firstarc){
int v =firstarc->adjvex;
if(distance[v]>distance[u]+firstarc->weight){
distance[v]=distance[u]+firstarc->weight;
}
firstarc=firstarc->next;
}
}
return distance;
}
使用stl中的priority_queue可以加快速度,参考代码
https://www.geeksforgeeks.org/dijkstras-shortest-path-algorithm-using-priority_queue-stl/
注意decrease-key的优先队列实现,以及pair的使用
// Program to find Dijkstra's shortest path using
// priority_queue in STL
#include<bits/stdc++.h>
using namespace std;
# define INF 0x3f3f3f3f
// iPair ==> Integer Pair
typedef pair<int, int> iPair;
// This class represents a directed graph using
// adjacency list representation
class Graph
{
int V; // No. of vertices
// In a weighted graph, we need to store vertex
// and weight pair for every edge
list< pair<int, int> > *adj;
public:
Graph(int V); // Constructor
// function to add an edge to graph
void addEdge(int u, int v, int w);
// prints shortest path from s
void shortestPath(int s);
};
// Allocates memory for adjacency list
Graph::Graph(int V)
{
this->V = V;
adj = new list<iPair> [V];
}
void Graph::addEdge(int u, int v, int w)
{
adj[u].push_back(make_pair(v, w));
adj[v].push_back(make_pair(u, w));
}
// Prints shortest paths from src to all other vertices
void Graph::shortestPath(int src)
{
// Create a priority queue to store vertices that
// are being preprocessed. This is weird syntax in C++.
// Refer below link for details of this syntax
// https://www.geeksforgeeks.org/implement-min-heap-using-stl/
priority_queue< iPair, vector <iPair> , greater<iPair> > pq;
// Create a vector for distances and initialize all
// distances as infinite (INF)
vector<int> dist(V, INF);
// Insert source itself in priority queue and initialize
// its distance as 0.
pq.push(make_pair(0, src));
dist[src] = 0;
/* Looping till priority queue becomes empty (or all
distances are not finalized) */
while (!pq.empty())
{
// The first vertex in pair is the minimum distance
// vertex, extract it from priority queue.
// vertex label is stored in second of pair (it
// has to be done this way to keep the vertices
// sorted distance (distance must be first item
// in pair)
int u = pq.top().second;
pq.pop();
// 'i' is used to get all adjacent vertices of a vertex
list< pair<int, int> >::iterator i;
for (i = adj[u].begin(); i != adj[u].end(); ++i)
{
// Get vertex label and weight of current adjacent
// of u.
int v = (*i).first;
int weight = (*i).second;
// If there is shorted path to v through u.
if (dist[v] > dist[u] + weight)
{
// Updating distance of v
dist[v] = dist[u] + weight;
pq.push(make_pair(dist[v], v));
}
}
}
// Print shortest distances stored in dist[]
printf("Vertex Distance from Source\n");
for (int i = 0; i < V; ++i)
printf("%d \t\t %d\n", i, dist[i]);
}
2. Prim算法
Prim和dijstra的不同之处,只有if判断时不同
思路是找最小的边,不断更新,blue rule的应用
维护一个cost数组和一个存最小生成树的邻接数组
void prim(int start,ALGraph & graph)
{
int sumweight=0;
int i,j,k=0;
int lowcost[graph.vexNum];
int adjecent[graph.vexNum];
for(i=0;i<graph.vexNum;i++)
{
lowcost[i]=graph.adjList[i].firstarc->weight;
visited[i]=-1; //将所有点至于Vnew之外,V之内,这里只要对应的为-1,就表示在Vnew之外
}
visited[start]=0; //将起始点start加入Vnew
adjecent[start]=start;
for(i=0;i<graph.vexNum-1;i++)
{
int min=INF;
int v=-1;
for(j=0;j<graph.vexNum;j++)
{
if(visited[j]!=-1&&lowcost[j]<min) //在Vnew之外寻找最短路径
{
min=lowcost[j];
v=j;
}
}
if(v!=-1)
{
printf("%d %d %d\n",adjecent[v],v,lowcost[v]);
visited[v]=1; //将v加Vnew中
sumweight+=lowcost[v]; //计算路径长度之和
ArcNode * firstarc=graph.adjList[v].firstarc;
while(firstarc){
int v =firstarc->adjvex;
if(visited[j]==-1&&firstarc->weight<lowcost[j]){
lowcost[j]=firstarc->weight; //此时v点加入Vnew 需要更新lowcost
adjecent[j]=v;
}
firstarc=firstarc->next;
}
}
}
printf("the minmum weight is %d",sumweight);
}
3. Kruskal算法
kruskal算法主要依靠并查集实现,下次课将涉及并查集相关知识
主要思想是把所有边进行排序,每次找最小的边,检查当前的边的两个端点是否在同一个连通分量中,如果不是,则将这个边加入MST中。
以下代码参考https://blog.csdn.net/luomingjun12315/article/details/47700237
//n为边的数量,m为村庄的数量
int Kruskal(int n, int m){
int nEdge = 0, res = 0;
//将边按照权值从小到大排序
qsort(a, n, sizeof(a[0]), cmp);
for(int i = 0; i < n && nEdge != m - 1; i++){
//判断当前这条边的两个端点是否属于同一棵树
if(find(a[i].a) != find(a[i].b)){
unite(a[i].a, a[i].b);
res += a[i].price;
nEdge++;
}
}
//如果加入边的数量小于m - 1,则表明该无向图不连通,等价于不存在最小生成树
if(nEdge < m-1) res = -1;
return res;
}
4. Reverse-delete算法
真正的red rule按照red rule去实现,但因为复杂度过高,没有什么应用。