最小生成树的prim和Kruskal算法
最小生成树
用最小的代价将图中的每一个点联通
我们有两种基于贪心策略的算法
Prim
-
初始化一点作为根节点
-
选择权值最小的与当前联通块相连的点加入到联通块中
-
如果图未遍历完成 则返回2
Kruskal
-
初始化图中所以的边 并按权值进行排序
-
遍历边的数组 如果当前边所连两点不连通 则将其连接
Prim代码
#include<bits/stdc++.h>
using namespace std;
const int maxn = 5050;
const int maxm = 200020;
int n,m;
struct Edge{
int from;
int to;
ll cost;
}edge[maxm];
bool cmp(Edge a,Edge b)
{
return a.cost<b.cost;
}
int fath[maxn]; //我们用并查集来维护当前两个点是否联通
void init()
{
for(int i=0;i<maxn;++i)
fath[i] = i;
}
int find(int f)
{
if(f==fath[f]) return f;
return fath[f] = find(fath[f]);
}
void unionSet(int a,int b)
{
int u = find(a), v = find(b);
if(u==v) return ;
fath[u] = v;
}
long long Kruskal()
{
long long ans = 0;
for(int i=1;i<=m;++i)
{
if(find(edge[i].from)==find(edge[i].to)) continue;//如果联通,则跳过当前边
unionSet(edge[i].from,edge[i].to); //两个点的集合合并
ans+=edge[i].cost;
}
return ans;
}
int main()
{
cin >> n >> m;
for(int i=1;i<=m;++i)
{
cin>>edge[i].from >> edge[i].to>>edge[i].cost;
}
init();
sort(edge+1,edge+1+m,cmp);
ll ans = Kruskal();
for(int i=1;i<=n;++i)
{
if(find(i)!=find(1)) ans = -1;
}//检查是否所以的点都联通
if(ans==-1) cout << "orz" << endl;
else cout << ans<<endl;
return 0;
}
Kruskal代码
#include<bits/stdc++.h>
using namespace std;
const int maxn = 5050;
const int maxm = 200020;
int n,m;
struct edge{
int to;
ll cost;
edge(int tt,ll cc):to(tt),cost(cc){ }
edge(){}
bool operator<(const edge &a)const{ //维护小根堆
return a.cost<cost;
}
};
bool vis[maxn]; //记录点是否加入
priority_queue<edge> que;
vector<edge> G[maxn]; //记录所有的边
ll prim()
{
ll ans = 0;
vis[1] = 1; //初始化 将1号点作为初始点
for(int i=0;i<G[1].size();++i) //将所有的边加入堆中
que.push(G[1][i]);
while(que.size())
{
edge e = que.top(); //获得当前最小的边
que.pop();
if(vis[e.to]) continue; //如果加入则挑过
vis[e.to] = 1;
ans += e.cost;
for(int i=0;i<G[e.to].size();++i) //将当前点所有的边加入堆中
que.push(G[e.to][i]);
}
return ans;
}
int main()
{
cin >> n >> m;
for(int i=0;i<=n;++i)
G[i].clear();
while(que.size()) que.pop();
for(int i=1;i<=m;++i)
{
int u,v;
ll cost;
cin >> u >> v >>cost;
G[u].push_back(edge(v,cost));//无向图 两个点都要加入
G[v].push_back(edge(u,cost));
}
ll ans = prim();
for(int i=1;i<=n;++i)
{
if(!vis[i]) ans = -1;
}
if(ans==-1) cout << "orz" <<endl;
else cout << ans<<endl;
return 0;
}