最小生成树,也就是求图里面用n-1条边使得整个图连接起来的算法。
两种算法,一种是kusual, 另一种是prim。
两种算法都很简单。
kusual : 简单来说就是我们先把所有的边排序,然后从小到大选出n-1条边使得图相连。
那么就是用优先队列维护最小,用并查集维护是否在同一个集合就好。
prim:主要思想和迪杰斯特拉是一样的,每次找最小的,没有被找到过的那一个边对应的点,然后用这个点去更新其余边的最小值。只是这里记录的是最短路里面上一个点到当前点的值。 证明麻烦得很,总之应该是贪心。
总之前人发明的东西真强啊。
这里用的是邻接矩阵存图,也可以用vector 或 链式前项星等方式,思想是一样的,不过是遍历方式换了。
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N = 5010;
int dist[N], vis[N], n, m;
const long long inf = 9 * 1e18;
int G[N][N];
int prim(){
for(int i = 1; i <= n; i++){
dist[i] = inf; vis[i] = 0;
}
for(int i = 2; i <= n; i++){
dist[i] = min(dist[i], G[1][i]);
}
int ans = 0; vis[1] = 1;
for(int i = 1; i < n; i++){
int now = -1, mn = inf;
for(int i = 1; i <= n; i++){
if(!vis[i] && dist[i] < mn){
mn = dist[i];
now = i;
}
}
if(now == -1) return -1;
ans += mn;
vis[now] = 1;
for(int i = 1; i <= n; i++){
if(!vis[i]){
dist[i] = min(dist[i], G[now][i]);
}
}
}
return ans;
}
signed main(){
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
memset(G, 0x3f, sizeof(G));
cin >> n >> m;
for(int i = 1; i <= m; i++){
int u, v, w;
cin >> u >> v >> w;
G[u][v] = G[v][u] = w;
}
int ans = prim();
if(ans == -1){
cout << "no ansers\n";
}else{
cout << ans << endl;
}
}
#include<bits/stdc++.h>
using namespace std;
const int N = 5010;
const long long inf = 9 * 1e18;
#define int long long
int n, m, dist[N], vis[N];
int G[N][N];
inline void add(int from, int to, int w){
G[from][to] = G[to][from] = w;
}
struct bb{
int dist, id;
bool operator < (const bb f) const{
return f.dist < dist;
}
};
//priority_queue<bb> q;
int prim(){
priority_queue<bb> q;
for(int i = 1; i <= n; i++){
dist[i] = inf; vis[i] = 0;
}
int ans = 0;
q.push({0, 1});
int cot = 0;
while(!q.empty()){
bb now = q.top();
q.pop();
if(vis[now.id]) continue;
vis[now.id] = 1;
ans += now.dist ; cot++;
if(cot == n) break;
for(int i = 1; i <= n; i++){
if(!vis[i] && G[now.id][i] < dist[i]){
dist[i] = G[now.id][i];
q.push({dist[i], i});
}
}
}
// while(!q.empty()) q.pop();
if(cot < n) return -1;
return ans;
}
signed main(){
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
memset(G, 0x3f, sizeof(G));
cin >> n >> m;
for(int i = 1; i <= m; i++){
int u, v, w;
cin >> u >> v >> w;
add(u, v, w); add(v, u, w);
}
int ans = prim();
cout << ans << endl;
}
代码思路就是这样,不断找最小的维护,一个是直接遍历,一个是优先队列维护最小。说实话,已经很简洁了。但是要注意的是优先队列的创建位置,要依据情况也就是数据大小决定。(放在里面肯定快)