一、最小生成树算法
1. Prim最小生成树算法(扩展点)
#include<iostream>
#include<algorithm>
#include<cmath>
#include<queue>
#include<stack>
#include<vector>
#include<string>
#include<deque>
using namespace std;
struct Edge
{
int head;
int tail;
int weight;
};
void readData(vector<vector<int>> & matrix)
{
int n = 6;
matrix.resize(n, vector<int>(n, INT_MAX));
for(int i = 0; i < n; i++)
{
matrix[i][i] = 0;
}
matrix[0][1] = 2;
matrix[1][0] = 2;
matrix[0][2] = 5;
matrix[2][0] = 5;
matrix[0][3] = 4;
matrix[3][0] = 4;
matrix[1][2] = 4;
matrix[2][1] = 4;
matrix[1][4] = 5;
matrix[4][1] = 5;
matrix[2][3] = 6;
matrix[3][2] = 6;
matrix[2][4] = 3;
matrix[4][2] = 3;
matrix[2][5] = 4;
matrix[5][2] = 4;
matrix[3][5] = 7;
matrix[5][3] = 7;
matrix[4][5] = 1;
matrix[5][4] = 1;
}
void printTree(vector<Edge>& tree)
{
for(int i = 0; i < tree.size(); i++)
{
cout<<tree[i].head<<" ---> "<<tree[i].tail<<"(weight = "<<tree[i].weight<<")"<<endl;
}
}
void prim(vector<vector<int>> &matrix, int s)
{
int n = matrix.size();
vector<int> minedge(n, 0);
vector<int> pre(n, 0);
vector<bool> visited(n, false);
vector<Edge> tree;
for(int i = 0; i < n; i++)
{
minedge[i] = matrix[s][i];
pre[i] = s;
}
minedge[s] = 0;
visited[s] = true;
for(int i = 0; i < n-1; i++)
{
int k = 0;
int minn = INT_MAX;
for(int j = 0; j < n; j++)
{
if(!visited[j] && minn > minedge[j])
{
minn = minedge[j];
k = j;
}
}
Edge t;
t.head = pre[k];
t.tail = k;
t.weight = minedge[k];
tree.push_back(t);
minedge[k] = 0;
visited[k] = true;
for(int j = 0; j < n; j++)
{
if(!visited[j] && matrix[k][j] < minedge[j])
{
minedge[j] = matrix[k][j];
pre[j] = k;
}
}
}
printTree(tree);
}
int main ()
{
vector<vector<int>> matrix;
readData(matrix);
prim(matrix, 0);
return 0;
}
2. Kruskal最小生成树算法(扩展边)
#include<iostream>
#include<algorithm>
#include<cmath>
#include<queue>
#include<stack>
#include<vector>
#include<string>
#include<deque>
using namespace std;
struct Edge
{
int head;
int tail;
int weight;
};
void readData(vector<vector<int>> & matrix)
{
int n = 6;
matrix.resize(n, vector<int>(n, INT_MAX));
for(int i = 0; i < n; i++)
{
matrix[i][i] = 0;
}
matrix[0][1] = 2;
matrix[1][0] = 2;
matrix[0][2] = 5;
matrix[2][0] = 5;
matrix[0][3] = 4;
matrix[3][0] = 4;
matrix[1][2] = 4;
matrix[2][1] = 4;
matrix[1][4] = 5;
matrix[4][1] = 5;
matrix[2][3] = 6;
matrix[3][2] = 6;
matrix[2][4] = 3;
matrix[4][2] = 3;
matrix[2][5] = 4;
matrix[5][2] = 4;
matrix[3][5] = 7;
matrix[5][3] = 7;
matrix[4][5] = 1;
matrix[5][4] = 1;
}
void printTree(vector<Edge>& tree)
{
for(int i = 0; i < tree.size(); i++)
{
cout<<tree[i].head<<" ---> "<<tree[i].tail<<"(weight = "<<tree[i].weight<<")"<<endl;
}
}
void getEdges(vector<vector<int>> &matrix, vector<Edge>& edges)
{
int n = matrix.size();
for(int i = 0; i < n; i++)
{
for(int j = i+1; j < n; j++)
{
if(matrix[i][j] != INT_MAX && matrix[i][j] != 0)
{
Edge e;
e.head = i;
e.tail = j;
e.weight = matrix[i][j];
edges.push_back(e);
}
}
}
}
struct cmp
{
bool operator()(const Edge& a, const Edge& b)
{
if(a.weight < b.weight)
return true;
return false;
}
};
void kruskal(vector<vector<int>> &matrix)
{
vector<Edge> tree;
vector<Edge> edges;
getEdges(matrix, edges);
sort(edges.begin(), edges.end(), cmp());
int n = matrix.size();
vector<int> components(n, 0);
for(int i = 0; i < n; i++)
components[i] = i;
int k = 0;
int j = 0;
while(k < n-1)
{
int h1 = edges[k].head;
int t1 = edges[k].tail;
int h2 = components[h1];
int t2 = components[t1];
if(h2 != t2)
{
Edge t;
t.head = h1;
t.tail = t1;
t.weight = edges[k].weight;
tree.push_back(t);
k++;
for(int i = 0; i < n; i++)
{
if(components[i] == t2)
components[i] = h2;
}
}
j++;
}
printTree(tree);
}
int main ()
{
vector<vector<int>> matrix;
readData(matrix);
kruskal(matrix);
return 0;
}
二、最短路径算法
1. Dijkstra单源最短路径算法(正权边)
#include<iostream>
#include<algorithm>
#include<cmath>
#include<queue>
#include<stack>
#include<vector>
#include<string>
#include<deque>
using namespace std;
void readData2(vector<vector<int>> & matrix)
{
int n = 5;
matrix.resize(n, vector<int>(n, INT_MAX));
for(int i = 0; i < n; i++)
{
matrix[i][i] = 0;
}
matrix[0][1] = 10;
matrix[0][3] = 30;
matrix[0][4] = 100;
matrix[1][2] = 50;
matrix[2][4] = 10;
matrix[3][2] = 20;
matrix[3][4] = 60;
}
void printPath(vector<int>& path, vector<int>& dist)
{
int n = path.size();
for(int i = n-1; i >= 1; i--)
{
vector<int> t;
int k = i;
while(k != -1)
{
t.insert(t.begin(),k);
k = path[k];
}
cout << t[0];
for(int j = 1; j < t.size(); j++)
cout << " ---> " << t[j];
cout<<"( dist = "<<dist[i]<<" )"<<endl;
}
}
void dijkstra(vector<vector<int>> &matrix, int s)
{
int n = matrix.size();
vector<int> dist(n, INT_MAX);
vector<int> visited(n, false);
vector<int> path(n, -1);
for(int i = 0; i < n; i++)
{
dist[i] = matrix[s][i];
if(dist[i] == INT_MAX || i == s)
path[i] = -1;
else
path[i] = s;
}
dist[s] = 0;
path[s] = -1;
visited[s] = true;
for(int i = 0; i < n-1; i++)
{
int minn = INT_MAX;
int pos = -1;
for(int j = 0; j < n; j++)
{
if(!visited[j] && minn > dist[j])
{
minn = dist[j];
pos = j;
}
}
visited[pos] = true;
for(int j = 0; j < n; j++)
{
if(!visited[j] && matrix[pos][j] != INT_MAX && dist[j] > dist[pos] + matrix[pos][j])
{
path[j] = pos;
dist[j] = dist[pos] + matrix[pos][j];
}
}
}
printPath(path,dist);
}
int main ()
{
vector<vector<int>> matrix;
readData2(matrix);
dijkstra(matrix, 0);
return 0;
}
2. BellmanFord单源最短路径算法(可判定负环)
#include<iostream>
#include<algorithm>
#include<cmath>
#include<queue>
#include<stack>
#include<vector>
#include<string>
#include<deque>
using namespace std;
struct Edge
{
int head;
int tail;
int weight;
};
void readData2(vector<vector<int>> & matrix)
{
int n = 5;
matrix.resize(n, vector<int>(n, INT_MAX));
for(int i = 0; i < n; i++)
{
matrix[i][i] = 0;
}
matrix[0][1] = 10;
matrix[0][3] = 30;
matrix[0][4] = 100;
matrix[1][2] = 50;
matrix[2][4] = 10;
matrix[3][2] = 20;
matrix[3][4] = -60;
}
void printPath(vector<int>& path, vector<int>& dist)
{
int n = path.size();
for(int i = n-1; i >= 1; i--)
{
vector<int> t;
int k = i;
while(k != -1)
{
t.insert(t.begin(),k);
k = path[k];
}
cout << t[0];
for(int j = 1; j < t.size(); j++)
cout << " ---> " << t[j];
cout<<"( dist = "<<dist[i]<<" )"<<endl;
}
}
void getEdges2(vector<vector<int>> &matrix, vector<Edge>& edges)
{
int n = matrix.size();
for(int i = 0; i < n; i++)
{
for(int j = 0; j < n; j++)
{
if(matrix[i][j] != INT_MAX && matrix[i][j] != 0)
{
Edge e;
e.head = i;
e.tail = j;
e.weight = matrix[i][j];
edges.push_back(e);
}
}
}
}
void bellmanFord(vector<vector<int>> &matrix, int s)
{
int n = matrix.size();
vector<Edge> edge;
getEdges2(matrix, edge);
vector<int> dist(n, INT_MAX);
vector<int> path(n, -1);
for(int i = 0; i < n; i++)
{
dist[i] = matrix[s][i];
if(dist[i] == INT_MAX || i == s)
path[i] = -1;
else
path[i] = s;
}
dist[s] = 0;
path[s] = -1;
for(int i = 0; i < n-1; i++)
{
for(int j = 0; j < edge.size(); j++)
{
int u = edge[j].head;
int v = edge[j].tail;
if(dist[u] != INT_MAX && dist[v] > dist[u] + edge[j].weight)
{
dist[v] = dist[u] + edge[j].weight;
path[v] = u;
}
}
}
for(int j = 0; j < edge.size(); j++)
{
int u = edge[j].head;
int v = edge[j].tail;
if(dist[u] != INT_MAX && dist[v] > dist[u] + edge[j].weight)
{
cout << "存在负环!" <<endl;
return;
}
}
printPath(path, dist);
}
int main ()
{
vector<vector<int>> matrix;
readData2(matrix);
bellmanFord(matrix, 0);
return 0;
}
3. SPFA算法SLF优化(可判定负环, 在部分情况下很快,但不具备普遍性)
#include<iostream>
#include<algorithm>
#include<cmath>
#include<queue>
#include<stack>
#include<vector>
#include<string>
#include<deque>
using namespace std;
void readData2(vector<vector<int>> & matrix)
{
int n = 5;
matrix.resize(n, vector<int>(n, INT_MAX));
for(int i = 0; i < n; i++)
{
matrix[i][i] = 0;
}
matrix[0][1] = 10;
matrix[0][3] = 30;
matrix[0][4] = 100;
matrix[1][2] = 50;
matrix[2][4] = 10;
matrix[3][2] = 20;
matrix[3][4] = -60;
}
void printPath(vector<int>& path, vector<int>& dist)
{
int n = path.size();
for(int i = n-1; i >= 1; i--)
{
vector<int> t;
int k = i;
while(k != -1)
{
t.insert(t.begin(),k);
k = path[k];
}
cout << t[0];
for(int j = 1; j < t.size(); j++)
cout << " ---> " << t[j];
cout<<"( dist = "<<dist[i]<<" )"<<endl;
}
}
void spfa(vector<vector<int>> &matrix, int s)
{
int n = matrix.size();
vector<int> dist(n, INT_MAX);
vector<int> path(n, -1);
vector<bool> visited(n, false);
vector<int> cnt(n, 0);
deque<int> q;
dist[s] = 0;
path[s] = -1;
visited[s] = true;
cnt[s]++;
q.push_back(s);
while(!q.empty())
{
int u = q.front();
q.pop_front();
visited[u] = false;
for(int v = 0; v < n; v++)
{
if(matrix[u][v] != INT_MAX)
{
if(dist[u] != INT_MAX && dist[v] > dist[u] + matrix[u][v])
{
dist[v] = dist[u] + matrix[u][v];
path[v] = u;
if(!visited[v])
{
if(q.empty())
q.push_back(v);
else
{
if(dist[v] < dist[q.front()])
q.push_front(v);
else
q.push_back(v);
}
visited[v] = true;
cnt[v]++;
if(cnt[v] >= n)
{
cout << "存在负环!" <<endl;
return;
}
}
}
}
}
}
printPath(path, dist);
}
int main ()
{
vector<vector<int>> matrix;
readData2(matrix);
spfa(matrix, 0);
return 0;
}
4. Floyd每对顶点间最短路径算法(可以有负权边,但不能有负环)
#include<iostream>
#include<algorithm>
#include<cmath>
#include<queue>
#include<stack>
#include<vector>
#include<string>
#include<deque>
using namespace std;
void readData2(vector<vector<int>> & matrix)
{
int n = 5;
matrix.resize(n, vector<int>(n, INT_MAX));
for(int i = 0; i < n; i++)
{
matrix[i][i] = 0;
}
matrix[0][1] = 10;
matrix[0][3] = 30;
matrix[0][4] = 100;
matrix[1][2] = 50;
matrix[2][4] = 10;
matrix[3][2] = 20;
matrix[3][4] = -60;
}
void printPath2(int u, int v, vector<vector<int>>& path)
{
if(path[u][v] == -1)
return;
printPath2(u, path[u][v], path);
cout << path[u][v] << " ---> ";
printPath2(path[u][v], v, path);
}
void floyd(vector<vector<int>> &matrix)
{
int n = matrix.size();
vector<vector<int>> dp(n, vector<int>(n, 0));
vector<vector<int>> path(n, vector<int>(n, -1));
for(int i = 0; i < n; i++)
{
for(int j = 0; j < n; j++)
{
dp[i][j] = matrix[i][j];
}
}
for(int k = 0; k < n; k++)
{
for(int i = 0; i < n; i++)
{
for(int j = 0; j < n; j++)
{
if((dp[i][k] != INT_MAX) && (dp[k][j] != INT_MAX) && (dp[i][j] > dp[i][k]+dp[k][j]))
{
dp[i][j] = dp[i][k]+dp[k][j];
path[i][j] = k;
}
}
}
}
for(int i = 0; i < n; i++)
{
for(int j = i+1; j < n; j++)
{
if(dp[i][j] < INT_MAX)
{
cout << i << " --> ";
printPath2(i,j,path);
cout<<j<<"( dist = " << dp[i][j] << " )"<<endl;
}
}
}
}
int main ()
{
vector<vector<int>> matrix;
readData2(matrix);
floyd(matrix);
return 0;
}
三、拓扑排序算法
#include<iostream>
#include<algorithm>
#include<cmath>
#include<queue>
#include<stack>
#include<vector>
#include<string>
#include<deque>
using namespace std;
struct Edge
{
int head;
int tail;
int weight;
};
void readData3(vector<vector<int>> & matrix)
{
int n = 7;
matrix.resize(n, vector<int>(n, INT_MAX));
for(int i = 0; i < n; i++)
{
matrix[i][i] = 0;
}
matrix[0][2] = 1;
matrix[2][3] = 1;
matrix[1][3] = 1;
matrix[1][6] = 1;
matrix[1][4] = 1;
matrix[3][4] = 1;
matrix[3][5] = 1;
matrix[6][5] = 1;
}
void getEdges2(vector<vector<int>> &matrix, vector<Edge>& edges)
{
int n = matrix.size();
for(int i = 0; i < n; i++)
{
for(int j = 0; j < n; j++)
{
if(matrix[i][j] != INT_MAX && matrix[i][j] != 0)
{
Edge e;
e.head = i;
e.tail = j;
e.weight = matrix[i][j];
edges.push_back(e);
}
}
}
}
void topoSort(vector<vector<int>>& matrix)
{
int n = matrix.size();
vector<int> arr;
vector<Edge> edge;
getEdges2(matrix, edge);
vector<int> indegree(n, 0);
queue<int> q;
for(int i = 0; i < edge.size(); i++)
indegree[edge[i].tail]++;
for(int i = 0; i < n; i++)
{
if(indegree[i] == 0)
q.push(i);
}
while(!q.empty())
{
int u = q.front();
q.pop();
arr.push_back(u);
for(int i = 0; i < edge.size(); i++)
{
if(edge[i].head == u)
{
int v = edge[i].tail;
indegree[v]--;
if(indegree[v] == 0)
q.push(v);
}
}
}
if(arr.size() == n)
{
cout << arr[0];
for(int i = 1; i < arr.size(); i++)
cout << " --> " << arr[i];
cout<<endl;
}
else
cout << "图中存在环路!" <<endl;
}
int main ()
{
vector<vector<int>> matrix;
readData3(matrix);
topoSort(matrix);
return 0;
}