摘要:
最小生成树模板——prime算法
最小生成树模板——krusal算法
题目简述:
算法分析:
prime算法和迪杰斯特拉算法有异曲同工之处,二者的本质都是贪心和动态规划。prime算法的思想可以概括为“逐步短接”,每一次选取当前遍历到的定点的最短的一条临边。
根据上述分析可知,由于每一次都会选取一条最短的边,因此可借鉴迪杰斯特拉算法的实现过程,采用隐式数据结构——堆,进行优化。详见代码
代码以及详细注释:
#include <iostream>
#include <stdio.h>
#include <vector>
#include <algorithm>
#include <queue>
#define INF 10000000
#pragma warning(disable:4996)
using namespace std;
/*链表前向星的准备工作*/
struct edge {
int to;
int next;
int w;
};
struct Node {
int pos; //点的编号
int w; //加入该点后,小增加的权值
Node(int _pos=0, int _w=0) :pos(_pos), w(_w) {}
bool operator()(Node& n1, Node& n2) {
return n1.w > n2.w; //准备建立一个小根堆
}
friend bool operator<(Node& n1, Node& n2)
{
return n1.w > n2.w; //准备建立一个小根堆
}
};
class Solution {
public:
int cnt=0;
vector<int> head;
vector<edge> e;
int n, m;
vector<int> dis;//这里的dis数组保存的并不是从起点到某点的距离。
//dis[i]表示的意思是加入第i个点后,最小生成树中增加的权值大小
vector<bool> visit;
priority_queue<Node, vector<Node>, Node> q;
int s = 1;
int count = 0; //假设起点s已经达到过
int ans = 0;
//链表前向星加边
inline void add_edge(int u, int v, int w) {
cnt++;
e[cnt].to = v;
e[cnt].w = w;
e[cnt].next = head[u];
head[u] = cnt;
}
void prime() {
cin >> n >> m;
e.resize(2*m + 1);
head.resize(n + 1, 0);
dis.resize(n + 1, INF);
visit.resize(n + 1, false);
for (int i = 1; i <= m; ++i)
{
int u, v, w;
cin >> u >> v >> w;
add_edge(u, v, w);
add_edge(v, u, w);
}
dis[1] = 0;
q.push(Node(1, 0));
//下面的过程同迪杰斯特拉算法
while (!q.empty() && count < n)
{
int u = q.top().pos;
int d = q.top().w;
q.pop();
if (visit[u]) continue;
visit[u] = true;
ans += d;
++count;
for (int i = head[u]; i != 0; i = e[i].next)
{
int y = e[i].to;
if (dis[y] > e[i].w)
{
dis[y] = e[i].w;
q.push(Node(y, dis[y]));
}
}
}
if (count == n)
cout << ans << endl;
else
cout << "orz" << endl;
}
};
int main() {
//freopen("in.txt", "r", stdin);
Solution s;
s.prime();
return 0;
}