最小生成树模板(prim + kruskal + prim堆优化)
prim适用于稠密图,kruskal适用于稀疏图
prim是以更新过的结点连边找最小值,kruskal是将边排序后从小到大选值
一.prim算法
hihocoder #1097 : 最小生成树一·Prim算法
1.利用邻接矩阵存储点与点之间的距离,例如:u -> v 距离为20,那么dist[u][v] = 20;
2.从起点出发,利用mincost[i]记录到第i个点的距离,并且将mincost[起点] = 0,其余赋值为INF
3.贪心的将距离集合(这里的集合是一个假想状态,可以认为是更新过的最短距离的点的集合)
最近的点u加入集合,然后将used[u] = 1,并且更新u附近的点的mincost[]
4.选择下一个离集合最近的且没被用过的点,重复第三步,直到所有联通点都被选择到就退出
code:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e3 + 10;
const int INF = 0x3f3f3f3f;
int n,mp[maxn][maxn],mincost[maxn],ans;
bool vis[maxn];
void prim()
{
for(int i = 1; i <= n; i++) mincost[i] = INF,vis[i] = false;
mincost[1] = 0;
ans = 0;
while(1){
int v = -1;
for(int i = 1; i <= n; i++){
if(!vis[i] && (v == -1 || mincost[i] < mincost[v]))
v = i;
}
if(v == -1) break;
vis[v] = true;
ans += mincost[v];
for(int i = 1; i <= n; i++)
mincost[i] = min(mincost[i],mp[v][i]);
}
}
int main()
{
cin>>n;
for(int i = 1; i <= n; i++)
{
for(int j = 1; j <= n; j++)
cin>>mp[i][j];
}
prim();
cout<<ans<<endl;
return 0;
}
二.kruskal算法
hihocoder #1098 : 最小生成树二·Kruscal算法
1.利用邻接表记录边的信息,并且按照边的权值的顺序从小到大排序
2.选择当前最小权值边,判断其两端的点是否属于同一个联通分量里面,这里使用并查集来判断和合并
3.假如不是属于同一个联通分量,就把他们两个点加在一个联通分量里,并且ans += 边的权值
4.重复2、3步,直到所有边都被判断了一次
code:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 10;
int n,m,fa[maxn],ans;
struct edge{
int u,v,cost;
};
edge e[1000010];
bool cmp(const edge &e1, const edge &e2)
{
return e1.cost < e2.cost;
}
void init()
{
ans = 0;
for(int i = 1; i <= n; i++)
fa[i] = i;
}
int find(int x)
{
return x == fa[x] ? x : fa[x] = find(fa[x]);
}
bool merge(int x,int y)
{
int xx = find(x);
int yy = find(y);
if(xx == yy) return false;
fa[yy] = xx;
return true;
}
void kr()
{
sort(e+1,e+1+m,cmp);
init();
for(int i = 1; i <= m; i++)
{
edge temp = e[i];
if(merge(temp.u,temp.v))
ans += temp.cost;
}
}
int main()
{
cin>>n>>m;
for(int i = 1; i <= m; i++)
cin>>e[i].u>>e[i].v>>e[i].cost;
kr();
cout<<ans<<endl;
return 0;
}
三.prim + 堆优化 + 链式前向星
hihocder #1109 : 最小生成树三·堆优化的Prim算法
1.其基本思路与prim一样,不过从邻接矩阵记录->链式前向星,然后用优先队列来维护mincost
code:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e6 + 10;
const int N = 1e5 + 10;
const int INF = 0x3f3f3f3f;
struct edge{
int to,dis,next;
}e[maxn<<1];
int n,m,head[N],dis[N],cnt,num,sum;
bool vis[maxn];
void add(int u,int v,int d)
{
e[++cnt].dis = d;
e[cnt].to = v;
e[cnt].next = head[u];
head[u] = cnt;
}
struct node{
int index,dist;
node(int a,int b){
index = a,dist = b;
}
bool operator < (const node &x) const{
return dist > x.dist;
}
};
void prim()
{
for(int i = 1; i <= n; i++) dis[i] = INF,vis[i] = false;
dis[1] = 0;
priority_queue <node> q;
q.push(node(1,0));
int num = 0;
while(!q.empty() && num < n)
{
node temp = q.top();
q.pop();
int x = temp.index, d = temp.dist;
if(vis[x]) continue;
vis[x] = true;
num++;
sum += d;
for(int i = head[x]; i ; i = e[i].next){
int y = e[i].to;
if(dis[y] > e[i].dis){
dis[y] = e[i].dis;
q.push(node(y,dis[y]));
}
}
}
}
int main()
{
cin>>n>>m;
for(int i = 1; i <= m; i++){
int u,v,d;
cin>>u>>v>>d;
add(u,v,d);
add(v,u,d);
}
prim();
cout<<sum<<endl;
return 0;
}