图论的类型
OI(竞赛编程)中的图论是一门研究图结构及其性质的学科,主要涉及到图的表示方法、图的遍历、最短路径、最小生成树、网络流等算法。下面我将详细介绍一些常见的OI图论算法。
一、图的表示方法
在OI中,常用的图的表示方法有邻接矩阵和邻接表两种。
1. 邻接矩阵:通过一个二维数组来表示图的连接关系。设图有n个顶点,那么邻接矩阵的大小为n×n。对于无向图,如果顶点i和顶点j之间有边相连,则邻接矩阵的第i行第j列和第j行第i列的值为1;否则为0。对于有向图,只需将邻接矩阵的对称位置改为1或0即可。
2. 邻接表:通过一个数组和一组链表来表示图的连接关系。数组的下标表示顶点的编号,数组的值表示链表的头指针。链表中存储的是与该顶点相连的其他顶点的编号。
二、图的遍历
图的遍历是指从图中的某一个顶点出发,按照某种规则依次访问图中的所有顶点。常见的图的遍历算法有深度优先搜索(DFS)和广度优先搜索(BFS)。
1. 深度优先搜索(DFS):从一个起始顶点开始,沿着某一条边一直遍历到底,直到不能再继续为止,然后回退到上一个顶点,继续遍历其他未遍历过的边。DFS可以使用递归或者栈来实现。
2. 广度优先搜索(BFS):从一个起始顶点开始,先访问该顶点,然后访问与该顶点相邻的所有未被访问过的顶点,再依次访问这些顶点的相邻顶点,直到所有顶点都被访问过为止。BFS可以使用队列来实现。
三、最短路径算法
最短路径算法是用来寻找图中两个顶点之间的最短路径的算法。常见的最短路径算法有Dijkstra算法和Floyd-Warshall算法。
1. Dijkstra算法:适用于求解单源最短路径问题,即从一个顶点到其他所有顶点的最短路径。Dijkstra算法使用贪心策略,每次选择当前距离最短的顶点进行扩展,直到所有顶点都被扩展为止。
2. Floyd-Warshall算法:适用于求解任意两个顶点之间的最短路径。Floyd-Warshall算法通过动态规划的方式,依次更新顶点之间的最短路径长度,直到所有顶点之间的最短路径都被计算出来。
四、最小生成树算法
最小生成树算法是用来寻找图中连接所有顶点的最小权重的连通子图的算法。常见的最小生成树算法有Prim算法和Kruskal算法。
1. Prim算法:适用于求解带权无向图的最小生成树。Prim算法从一个起始顶点开始,每次选择与当前生成树相连的最短边所连接的顶点,直到所有顶点都被加入到生成树为止。
2. Kruskal算法:适用于求解带权无向图的最小生成树。Kruskal算法通过不断选择权重最小的边,并判断该边的两个顶点是否在同一个连通分量中,直到所有顶点都被加入到生成树为止。
五、网络流算法
网络流算法是用来求解网络中最大流或最小割的算法。常见的网络流算法有Ford-Fulkerson算法和Edmonds-Karp算法。
1. Ford-Fulkerson算法:Ford-Fulkerson算法通过不断寻找增广路径来增加流量,直到无法找到增广路径为止。该算法的时间复杂度取决于增广路径的选择策略。
2. Edmonds-Karp算法:Edmonds-Karp算法是Ford-Fulkerson算法的一种实现方式,它选择的增广路径是基于BFS遍历的最短路径。相比于Ford-Fulkerson算法,Edmonds-Karp算法的时间复杂度更稳定。
注:本文章中只涉及最短路径算法与最小生成树算法
图论的基本概念
图论是一门研究图结构及其性质的学科,是竞赛编程中非常重要的一个领域。在OI(竞赛编程)中,图论常常用于解决各种与图相关的问题,如最短路径、最小生成树、网络流等。
图是由顶点和边组成的一种数据结构。顶点表示图中的元素,边表示顶点之间的关系。图可以分为有向图和无向图两种类型。
1. 有向图:顶点之间的关系是有方向的,即从一个顶点到另一个顶点有一条有向边。在有向图中,边有起点和终点的概念。
2. 无向图:顶点之间的关系是无方向的,即从一个顶点到另一个顶点有一条无向边。在无向图中,边没有起点和终点的概念,边的两个端点可以互相到达。
图论的图
有向图(Directed Graph)是由一组顶点和一组有向边组成的图结构。有向边是有方向的,表示从一个顶点到另一个顶点的关系。在有向图中,边有起点和终点的概念。例如,如果有一条从顶点A到顶点B的有向边,那么可以从A到B,但不能从B到A。有向图可以用以下方式表示:
1. 邻接矩阵(Adjacency Matrix):使用一个二维数组来表示图的连接关系。对于有向图,邻接矩阵的第i行第j列的值表示从顶点i到顶点j是否有边。
2. 邻接表(Adjacency List):使用一个数组和一组链表来表示图的连接关系。数组的每个元素表示一个顶点,链表中存储与该顶点相邻的其他顶点。
有向图常用于表示有向关系,如有向图中的边可以表示一个事件的发生顺序或一个任务的依赖关系。在有向图中,常见的算法有拓扑排序和强连通分量等。
无向图(Undirected Graph)是由一组顶点和一组无向边组成的图结构。无向边是无方向的,表示顶点之间的对等关系。在无向图中,边没有起点和终点的概念,边的两个端点可以互相到达。例如,如果有一条连接顶点A和顶点B的无向边,那么可以从A到B,也可以从B到A。无向图可以用以下方式表示:
1. 邻接矩阵(Adjacency Matrix):使用一个二维数组来表示图的连接关系。对于无向图,邻接矩阵是对称的,即第i行第j列的值和第j行第i列的值相等,表示顶点i和顶点j之间有边。
2. 邻接表(Adjacency List):使用一个数组和一组链表来表示图的连接关系。数组的每个元素表示一个顶点,链表中存储与该顶点相邻的其他顶点。
无向图常用于表示无方向关系,如无向图中的边可以表示两个元素之间的相似性或关联性。在无向图中,常见的算法有最小生成树、连通性判断和最短路径等。
来看下面的图:
图论的时空间复杂度
在图论中,算法的时空间复杂度是评估算法执行时间和占用内存空间的指标。时空间复杂度的分析可以帮助我们评估算法的效率和可行性。
时空间复杂度的表示通常使用大O符号(O-notation)来表示。以下是常见的图论算法的时空间复杂度分析:
1. 深度优先搜索(DFS)和广度优先搜索(BFS):
- 时间复杂度:O(V + E),其中V是顶点数,E是边数。在最坏情况下,需要遍历所有的顶点和边。
- 空间复杂度:O(V),其中V是顶点数。在DFS中,需要使用递归栈或显式栈来存储遍历的顶点,所以空间复杂度与顶点数相关。
2. 最短路径算法(如Dijkstra算法和Floyd-Warshall算法):
- 时间复杂度:O((V + E)logV) 或 O(V^3),取决于具体算法的实现方式。Dijkstra算法使用优先队列来选择下一个顶点,所以时间复杂度与顶点数和边数相关;Floyd-Warshall算法使用三层循环来计算最短路径,所以时间复杂度与顶点数的立方相关。
- 空间复杂度:O(V^2) 或 O(V^3),取决于具体算法的实现方式。Dijkstra算法使用一个数组来存储最短路径,所以空间复杂度与顶点数的平方相关;Floyd-Warshall算法使用一个二维数组来存储最短路径,所以空间复杂度与顶点数的立方相关。
3. 最小生成树算法(如Prim算法和Kruskal算法):
- 时间复杂度:O((V + E)logV) 或 O(ElogV),取决于具体算法的实现方式。Prim算法使用优先队列来选择下一个顶点,所以时间复杂度与顶点数和边数相关;Kruskal算法使用并查集来判断边的连通性,所以时间复杂度与边数相关。
- 空间复杂度:O(V) 或 O(E),取决于具体算法的实现方式。Prim算法使用一个数组来存储最小生成树的顶点,所以空间复杂度与顶点数相关;Kruskal算法使用并查集来存储边的连通性,所以空间复杂度与边数相关。
4. 网络流算法(如Ford-Fulkerson算法和Edmonds-Karp算法):
- 时间复杂度:O(E * f),其中E是边数,f是最大流量。在最坏情况下,需要多次增广路径来找到最大流。
- 空间复杂度:O(V^2) 或 O(V^3),取决于具体算法的实现方式。Ford-Fulkerson算法和Edmonds-Karp算法都使用一个二维数组来存储图的容量和流量,所以空间复杂度与顶点数的平方或立方相关。
需要注意的是,以上复杂度分析是一般情况下的估计,具体的实现方式和问题规模可能会影响实际的复杂度。在实际应用中,可以根据具体问题的规模和要求,选择合适的算法和数据结构来提高效率和节省内存空间。
终于到了同学们最爱的算法实现环节了
图论的算法实现
Floyd:
// C++ Program for Floyd Warshall Algorithm
#include <bits/stdc++.h>
using namespace std;
#define V 4
#define INF 99999
void floydWarshall(int dist[][V])
{
int i, j, k;
for (k = 0; k < V; k++) {
for (i = 0; i < V; i++) {
for (j = 0; j < V; j++) {
if (dist[i][j] > (dist[i][k] + dist[k][j])
&& (dist[k][j] != INF
&& dist[i][k] != INF))
dist[i][j] = dist[i][k] + dist[k][j];
}
}
}
printSolution(dist);
}
void printSolution(int dist[][V])
{
cout << "The following matrix shows the shortest "
"distances"
" between every pair of vertices \n";
for (int i = 0; i < V; i++) {
for (int j = 0; j < V; j++) {
if (dist[i][j] == INF)
cout << "INF"
<< " ";
else
cout << dist[i][j] << " ";
}
cout << endl;
}
}
int main()
{
int graph[V][V] = { { 0, 5, INF, 10 },
{ INF, 0, 3, INF },
{ INF, INF, 0, 1 },
{ INF, INF, INF, 0 } };
floydWarshall(graph);
return 0;
}
Bellman–Ford
// A C++ program for Bellman-Ford's single source
#include <bits/stdc++.h>
using namespace std;
struct Edge {
int src, dest, weight;
};
struct Graph {
int V, E;
struct Edge* edge;
};
struct Graph* createGraph(int V, int E)
{
struct Graph* graph = new Graph;
graph->V = V;
graph->E = E;
graph->edge = new Edge[E];
return graph;
}
void printArr(int dist[], int n)
{
printf("Vertex Distance from Source\n");
for (int i = 0; i < n; ++i)
printf("%d \t\t %d\n", i, dist[i]);
}
void BellmanFord(struct Graph* graph, int src)
{
int V = graph->V;
int E = graph->E;
int dist[V];
for (int i = 0; i < V; i++)
dist[i] = INT_MAX;
dist[src] = 0;
for (int i = 1; i <= V - 1; i++) {
for (int j = 0; j < E; j++) {
int u = graph->edge[j].src;
int v = graph->edge[j].dest;
int weight = graph->edge[j].weight;
if (dist[u] != INT_MAX
&& dist[u] + weight < dist[v])
dist[v] = dist[u] + weight;
}
}
for (int i = 0; i < E; i++) {
int u = graph->edge[i].src;
int v = graph->edge[i].dest;
int weight = graph->edge[i].weight;
if (dist[u] != INT_MAX
&& dist[u] + weight < dist[v]) {
printf("Graph contains negative weight cycle");
return;
}
}
printArr(dist, V);
return;
}
int main()
{
int V = 5; // Number of vertices in graph
int E = 8; // Number of edges in graph
struct Graph* graph = createGraph(V, E);
graph->edge[0].src = 0;
graph->edge[0].dest = 1;
graph->edge[0].weight = -1;
graph->edge[1].src = 0;
graph->edge[1].dest = 2;
graph->edge[1].weight = 4;
graph->edge[2].src = 1;
graph->edge[2].dest = 2;
graph->edge[2].weight = 3;
graph->edge[3].src = 1;
graph->edge[3].dest = 3;
graph->edge[3].weight = 2;
graph->edge[4].src = 1;
graph->edge[4].dest = 4;
graph->edge[4].weight = 2;
graph->edge[5].src = 3;
graph->edge[5].dest = 2;
graph->edge[5].weight = 5;
graph->edge[6].src = 3;
graph->edge[6].dest = 1;
graph->edge[6].weight = 1;
graph->edge[7].src = 4;
graph->edge[7].dest = 3;
graph->edge[7].weight = -3;
BellmanFord(graph, 0);
return 0;
}
Prim’s Algorithm
// A C++ program for Prim's Minimum
#include <bits/stdc++.h>
using namespace std;
#define V 5
int minKey(int key[], bool mstSet[])
{
// Initialize min value
int min = INT_MAX, min_index;
for (int v = 0; v < V; v++)
if (mstSet[v] == false && key[v] < min)
min = key[v], min_index = v;
return min_index;
}
void printMST(int parent[], int graph[V][V])
{
cout << "Edge \tWeight\n";
for (int i = 1; i < V; i++)
cout << parent[i] << " - " << i << " \t"
<< graph[i][parent[i]] << " \n";
}
void primMST(int graph[V][V])
{
int parent[V];
int key[V];
bool mstSet[V];
for (int i = 0; i < V; i++)
key[i] = INT_MAX, mstSet[i] = false;
key[0] = 0;
parent[0] = -1;
for (int count = 0; count < V - 1; count++) {
int u = minKey(key, mstSet);
mstSet[u] = true;
for (int v = 0; v < V; v++)
if (graph[u][v] && mstSet[v] == false
&& graph[u][v] < key[v])
parent[v] = u, key[v] = graph[u][v];
}
printMST(parent, graph);
}
int main()
{
int graph[V][V] = { { 0, 2, 0, 6, 0 },
{ 2, 0, 3, 8, 5 },
{ 0, 3, 0, 0, 7 },
{ 6, 8, 0, 0, 9 },
{ 0, 5, 7, 9, 0 } };
primMST(graph);
return 0;
}
Kruskal
// C++ program for the above approach Kruskal
#include <bits/stdc++.h>
using namespace std;
class DSU {
int* parent;
int* rank;
public:
DSU(int n)
{
parent = new int[n];
rank = new int[n];
for (int i = 0; i < n; i++) {
parent[i] = -1;
rank[i] = 1;
}
}
int find(int i)
{
if (parent[i] == -1)
return i;
return parent[i] = find(parent[i]);
}
void unite(int x, int y)
{
int s1 = find(x);
int s2 = find(y);
if (s1 != s2) {
if (rank[s1] < rank[s2]) {
parent[s1] = s2;
}
else if (rank[s1] > rank[s2]) {
parent[s2] = s1;
}
else {
parent[s2] = s1;
rank[s1] += 1;
}
}
}
};
class Graph {
vector<vector<int> > edgelist;
int V;
public:
Graph(int V) { this->V = V; }
void addEdge(int x, int y, int w)
{
edgelist.push_back({ w, x, y });
}
void kruskals_mst()
{
sort(edgelist.begin(), edgelist.end());
DSU s(V);
int ans = 0;
cout << "Following are the edges in the "
"constructed MST"
<< endl;
for (auto edge : edgelist) {
int w = edge[0];
int x = edge[1];
int y = edge[2];
if (s.find(x) != s.find(y)) {
s.unite(x, y);
ans += w;
cout << x << " -- " << y << " == " << w
<< endl;
}
}
cout << "Minimum Cost Spanning Tree: " << ans;
}
};
int main()
{
Graph g(4);
g.addEdge(0, 1, 10);
g.addEdge(1, 3, 15);
g.addEdge(2, 3, 4);
g.addEdge(2, 0, 6);
g.addEdge(0, 3, 5);
// Function call
g.kruskals_mst();
return 0;
}
Minimum Cut(最小割)
// C++ program for finding minimum cut using Ford-Fulkerson
#include <iostream>
#include <limits.h>
#include <string.h>
#include <queue>
using namespace std;
#define V 6
int bfs(int rGraph[V][V], int s, int t, int parent[])
{
bool visited[V];
memset(visited, 0, sizeof(visited));
queue <int> q;
q.push(s);
visited[s] = true;
parent[s] = -1;
while (!q.empty())
{
int u = q.front();
q.pop();
for (int v=0; v<V; v++)
{
if (visited[v]==false && rGraph[u][v] > 0)
{
q.push(v);
parent[v] = u;
visited[v] = true;
}
}
}
return (visited[t] == true);
}
void dfs(int rGraph[V][V], int s, bool visited[])
{
visited[s] = true;
for (int i = 0; i < V; i++)
if (rGraph[s][i] && !visited[i])
dfs(rGraph, i, visited);
}
void minCut(int graph[V][V], int s, int t)
{
int u, v;
int rGraph[V][V]; // rGraph[i][j] indicates residual capacity of edge i-j
for (u = 0; u < V; u++)
for (v = 0; v < V; v++)
rGraph[u][v] = graph[u][v];
int parent[V]; // This array is filled by BFS and to store path
while (bfs(rGraph, s, t, parent))
{
int path_flow = INT_MAX;
for (v=t; v!=s; v=parent[v])
{
u = parent[v];
path_flow = min(path_flow, rGraph[u][v]);
}
for (v=t; v != s; v=parent[v])
{
u = parent[v];
rGraph[u][v] -= path_flow;
rGraph[v][u] += path_flow;
}
}
bool visited[V];
memset(visited, false, sizeof(visited));
dfs(rGraph, s, visited);
for (int i = 0; i < V; i++)
for (int j = 0; j < V; j++)
if (visited[i] && !visited[j] && graph[i][j])
cout << i << " - " << j << endl;
return;
}
int main()
{
// Let us create a graph shown in the above example
int graph[V][V] = { {0, 16, 13, 0, 0, 0},
{0, 0, 10, 12, 0, 0},
{0, 4, 0, 0, 14, 0},
{0, 0, 9, 0, 0, 20},
{0, 0, 0, 7, 0, 4},
{0, 0, 0, 0, 0, 0}
};
minCut(graph, 0, 5);
return 0;
}
Ford-Fulkerson Algorithm(最大流)
// C++ program for implementation of Ford Fulkerson
#include <bits/stdc++.h>
using namespace std;
#define V 6
bool bfs(int rGraph[V][V], int s, int t, int parent[])
{
bool visited[V];
memset(visited, 0, sizeof(visited));
queue<int> q;
q.push(s);
visited[s] = true;
parent[s] = -1;
while (!q.empty()) {
int u = q.front();
q.pop();
for (int v = 0; v < V; v++) {
if (visited[v] == false && rGraph[u][v] > 0) {
if (v == t) {
parent[v] = u;
return true;
}
q.push(v);
parent[v] = u;
visited[v] = true;
}
}
}
return false;
}
int fordFulkerson(int graph[V][V], int s, int t)
{
int u, v;
int rGraph[V][V];
for (u = 0; u < V; u++)
for (v = 0; v < V; v++)
rGraph[u][v] = graph[u][v];
int parent[V];
int max_flow = 0;
while (bfs(rGraph, s, t, parent)) {
int path_flow = INT_MAX;
for (v = t; v != s; v = parent[v]) {
u = parent[v];
path_flow = min(path_flow, rGraph[u][v]);
}
for (v = t; v != s; v = parent[v]) {
u = parent[v];
rGraph[u][v] -= path_flow;
rGraph[v][u] += path_flow;
}
max_flow += path_flow;
}
return max_flow;
}
int main()
{
int graph[V][V]
= { { 0, 16, 13, 0, 0, 0 }, { 0, 0, 10, 12, 0, 0 },
{ 0, 4, 0, 0, 14, 0 }, { 0, 0, 9, 0, 0, 20 },
{ 0, 0, 0, 7, 0, 4 }, { 0, 0, 0, 0, 0, 0 } };
cout << "The maximum possible flow is "
<< fordFulkerson(graph, 0, 5);
return 0;
}
Strongly Connected Components(强连通分量)
#include <bits/stdc++.h>
using namespace std;
class GFG {
public:
bool dfs(int curr, int des, vector<vector<int> >& adj,
vector<int>& vis)
{
if (curr == des) {
return true;
}
vis[curr] = 1;
for (auto x : adj[curr]) {
if (!vis[x]) {
if (dfs(x, des, adj, vis)) {
return true;
}
}
}
return false;
}
bool isPath(int src, int des, vector<vector<int> >& adj)
{
vector<int> vis(adj.size() + 1, 0);
return dfs(src, des, adj, vis);
}
vector<vector<int> > findSCC(int n,
vector<vector<int> >& a)
{
vector<vector<int> > ans;
vector<int> is_scc(n + 1, 0);
vector<vector<int> > adj(n + 1);
for (int i = 0; i < a.size(); i++) {
adj[a[i][0]].push_back(a[i][1]);
}
for (int i = 1; i <= n; i++) {
if (!is_scc[i]) {
vector<int> scc;
scc.push_back(i);
for (int j = i + 1; j <= n; j++) {
if (!is_scc[j] && isPath(i, j, adj)
&& isPath(j, i, adj)) {
is_scc[j] = 1;
scc.push_back(j);
}
}
ans.push_back(scc);
}
}
return ans;
}
};
int main()
{
GFG obj;
int V = 5;
vector<vector<int> > edges{
{ 1, 3 }, { 1, 4 }, { 2, 1 }, { 3, 2 }, { 4, 5 }
};
vector<vector<int> > ans = obj.findSCC(V, edges);
cout << "Strongly Connected Components are:\n";
for (auto x : ans) {
for (auto y : x) {
cout << y << " ";
}
cout << "\n";
}
}
Topological Sort(拓扑排序)
// A C++ program to print topological
#include <bits/stdc++.h>
using namespace std;
class Graph {
int V;
list<int>* adj;
void topologicalSortUtil(int v, bool visited[],
stack<int>& Stack);
public:
Graph(int V);
void addEdge(int v, int w);
void topologicalSort();
};
Graph::Graph(int V)
{
this->V = V;
adj = new list<int>[V];
}
void Graph::addEdge(int v, int w)
{
adj[v].push_back(w);
}
void Graph::topologicalSortUtil(int v, bool visited[],
stack<int>& Stack)
{
visited[v] = true;
list<int>::iterator i;
for (i = adj[v].begin(); i != adj[v].end(); ++i)
if (!visited[*i])
topologicalSortUtil(*i, visited, Stack);
Stack.push(v);
}
void Graph::topologicalSort()
{
stack<int> Stack;
bool* visited = new bool[V];
for (int i = 0; i < V; i++)
visited[i] = false;
for (int i = 0; i < V; i++)
if (visited[i] == false)
topologicalSortUtil(i, visited, Stack);
while (Stack.empty() == false) {
cout << Stack.top() << " ";
Stack.pop();
}
delete [] visited;
}
int main()
{
Graph g(6);
g.addEdge(5, 2);
g.addEdge(5, 0);
g.addEdge(4, 0);
g.addEdge(4, 1);
g.addEdge(2, 3);
g.addEdge(3, 1);
cout << "Following is a Topological Sort of the given "
"graph \n";
g.topologicalSort();
return 0;
}
Dijstras
// C++ Program to find Dijkstra's shortest path using
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
typedef pair<int, int> iPair;
class Graph {
int V; // No. of vertices
list<pair<int, int> >* adj;
public:
Graph(int V); // Constructor
void addEdge(int u, int v, int w);
void shortestPath(int s);
};
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));
}
void Graph::shortestPath(int src)
{
priority_queue<iPair, vector<iPair>, greater<iPair> >
pq;
vector<int> dist(V, INF);
pq.push(make_pair(0, src));
dist[src] = 0;
while (!pq.empty()) {
int u = pq.top().second;
pq.pop();
list<pair<int, int> >::iterator i;
for (i = adj[u].begin(); i != adj[u].end(); ++i) {
int v = (*i).first;
int weight = (*i).second;
if (dist[v] > dist[u] + weight) {
dist[v] = dist[u] + weight;
pq.push(make_pair(dist[v], v));
}
}
}
printf("Vertex Distance from Source\n");
for (int i = 0; i < V; ++i)
printf("%d \t\t %d\n", i, dist[i]);
}
int main()
{
int V = 9;
Graph g(V);
g.addEdge(0, 1, 4);
g.addEdge(0, 7, 8);
g.addEdge(1, 2, 8);
g.addEdge(1, 7, 11);
g.addEdge(2, 3, 7);
g.addEdge(2, 8, 2);
g.addEdge(2, 5, 4);
g.addEdge(3, 4, 9);
g.addEdge(3, 5, 14);
g.addEdge(4, 5, 10);
g.addEdge(5, 6, 2);
g.addEdge(6, 7, 1);
g.addEdge(6, 8, 6);
g.addEdge(7, 8, 7);
g.shortestPath(0);
return 0;
}
2
//C++ program for Dijkstra's
#include <bits/stdc++.h>
struct AdjListNode
{
int dest;
int weight;
struct AdjListNode* next;
};
struct AdjList
{
struct AdjListNode *head;
};
struct Graph
{
int V;
struct AdjList* array;
};
struct AdjListNode* newAdjListNode(
int dest, int weight)
{
struct AdjListNode* newNode =
(struct AdjListNode*)
malloc(sizeof(struct AdjListNode));
newNode->dest = dest;
newNode->weight = weight;
newNode->next = NULL;
return newNode;
}
struct Graph* createGraph(int V)
{
struct Graph* graph = (struct Graph*)
malloc(sizeof(struct Graph));
graph->V = V;
graph->array = (struct AdjList*)
malloc(V * sizeof(struct AdjList));
for (int i = 0; i < V; ++i)
graph->array[i].head = NULL;
return graph;
}
// Adds an edge to an undirected graph
void addEdge(struct Graph* graph, int src,
int dest, int weight)
{
struct AdjListNode* newNode =
newAdjListNode(dest, weight);
newNode->next = graph->array[src].head;
graph->array[src].head = newNode;
newNode = newAdjListNode(src, weight);
newNode->next = graph->array[dest].head;
graph->array[dest].head = newNode;
}
struct MinHeapNode
{
int v;
int dist;
};
struct MinHeap
{
int size;
int capacity;
int *pos;
struct MinHeapNode **array;
};
struct MinHeapNode* newMinHeapNode(int v,
int dist)
{
struct MinHeapNode* minHeapNode =
(struct MinHeapNode*)
malloc(sizeof(struct MinHeapNode));
minHeapNode->v = v;
minHeapNode->dist = dist;
return minHeapNode;
}
struct MinHeap* createMinHeap(int capacity)
{
struct MinHeap* minHeap =
(struct MinHeap*)
malloc(sizeof(struct MinHeap));
minHeap->pos = (int *)malloc(
capacity * sizeof(int));
minHeap->size = 0;
minHeap->capacity = capacity;
minHeap->array =
(struct MinHeapNode**)
malloc(capacity *
sizeof(struct MinHeapNode*));
return minHeap;
}
void swapMinHeapNode(struct MinHeapNode** a,
struct MinHeapNode** b)
{
struct MinHeapNode* t = *a;
*a = *b;
*b = t;
}
void minHeapify(struct MinHeap* minHeap,
int idx)
{
int smallest, left, right;
smallest = idx;
left = 2 * idx + 1;
right = 2 * idx + 2;
if (left < minHeap->size &&
minHeap->array[left]->dist <
minHeap->array[smallest]->dist )
smallest = left;
if (right < minHeap->size &&
minHeap->array[right]->dist <
minHeap->array[smallest]->dist )
smallest = right;
if (smallest != idx)
{
MinHeapNode *smallestNode =
minHeap->array[smallest];
MinHeapNode *idxNode =
minHeap->array[idx];
minHeap->pos[smallestNode->v] = idx;
minHeap->pos[idxNode->v] = smallest;
swapMinHeapNode(&minHeap->array[smallest],
&minHeap->array[idx]);
minHeapify(minHeap, smallest);
}
}
int isEmpty(struct MinHeap* minHeap)
{
return minHeap->size == 0;
}
struct MinHeapNode* extractMin(struct MinHeap*
minHeap)
{
if (isEmpty(minHeap))
return NULL;
struct MinHeapNode* root =
minHeap->array[0];
struct MinHeapNode* lastNode =
minHeap->array[minHeap->size - 1];
minHeap->array[0] = lastNode;
minHeap->pos[root->v] = minHeap->size-1;
minHeap->pos[lastNode->v] = 0;
--minHeap->size;
minHeapify(minHeap, 0);
return root;
}
void decreaseKey(struct MinHeap* minHeap,
int v, int dist)
{
int i = minHeap->pos[v];
minHeap->array[i]->dist = dist;
while (i && minHeap->array[i]->dist <
minHeap->array[(i - 1) / 2]->dist)
{
// Swap this node with its parent
minHeap->pos[minHeap->array[i]->v] =
(i-1)/2;
minHeap->pos[minHeap->array[
(i-1)/2]->v] = i;
swapMinHeapNode(&minHeap->array[i],
&minHeap->array[(i - 1) / 2]);
i = (i - 1) / 2;
}
}
bool isInMinHeap(struct MinHeap *minHeap, int v)
{
if (minHeap->pos[v] < minHeap->size)
return true;
return false;
}
void printArr(int dist[], int n)
{
printf("Vertex Distance from Source\n");
for (int i = 0; i < n; ++i)
printf("%d \t\t %d\n", i, dist[i]);
}
void dijkstra(struct Graph* graph, int src)
{
int V = graph->V;
int dist[V];
struct MinHeap* minHeap = createMinHeap(V);
for (int v = 0; v < V; ++v)
{
dist[v] = INT_MAX;
minHeap->array[v] = newMinHeapNode(v,
dist[v]);
minHeap->pos[v] = v;
}
minHeap->array[src] =
newMinHeapNode(src, dist[src]);
minHeap->pos[src] = src;
dist[src] = 0;
decreaseKey(minHeap, src, dist[src]);
minHeap->size = V;
while (!isEmpty(minHeap))
{
struct MinHeapNode* minHeapNode =
extractMin(minHeap);
int u = minHeapNode->v;
struct AdjListNode* pCrawl =
graph->array[u].head;
while (pCrawl != NULL)
{
int v = pCrawl->dest;
if (isInMinHeap(minHeap, v) &&
dist[u] != INT_MAX &&
pCrawl->weight + dist[u] < dist[v])
{
dist[v] = dist[u] + pCrawl->weight;
decreaseKey(minHeap, v, dist[v]);
}
pCrawl = pCrawl->next;
}
}
printArr(dist, V);
}
int main()
{
int V = 9;
struct Graph* graph = createGraph(V);
addEdge(graph, 0, 1, 4);
addEdge(graph, 0, 7, 8);
addEdge(graph, 1, 2, 8);
addEdge(graph, 1, 7, 11);
addEdge(graph, 2, 3, 7);
addEdge(graph, 2, 8, 2);
addEdge(graph, 2, 5, 4);
addEdge(graph, 3, 4, 9);
addEdge(graph, 3, 5, 14);
addEdge(graph, 4, 5, 10);
addEdge(graph, 5, 6, 2);
addEdge(graph, 6, 7, 1);
addEdge(graph, 6, 8, 6);
addEdge(graph, 7, 8, 7);
dijkstra(graph, 0);
return 0;
}