算法记录——图算法(最小生成树、最短路径、拓扑排序)

一、最小生成树算法

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;  //[4][3]即有负环
}

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;  //[4][3]即有负环
}

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()])  //SLF优化
								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;  //改成[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;
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值