DAY 7
1.AcWing 858 prim算法求最小生成树
考察点:prim算法 主要针对于稠密图
最小生成树与二分图学习总体框架:
基础知识:朴素prim算法
prim算法与Dijkstra算法的区别在于,前者用更新的是后续点到集合的距离,后者更新的是到起点的距离。
在写代码的时候需要注意的一点是:为了防止出现自环,必须先累加距离再更新最小生成树、
最终实现代码:
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 510,INF = 0x3f3f3f3f;
int n,m;
int g[N][N];//稠密图用邻接矩阵保存;
int dist[N];
bool st[N];
int prim()
{
memset(dist,0x3f,sizeof dist);
int res = 0;//用来存储总距离
for(int i = 0;i<n;i++)
{
int t = -1;//初始化中转站t
for(int j = 1;j<=n;j++)
if(!st[j]&&(t == -1||dist[t]>dist[j]))
t = j;//更新
if(i&&dist[t] == INF) return INF;//防止是第一个点 如果没有生成树则返回
if(i)res += dist[t];
st[t] = true;
for(int j = 1;j<=n;j++)
dist[j] = min(dist[j],g[t][j]);//先累加再更新,防止出现自环
}
return res;
}
int main()
{
scanf("%d%d",&n,&m);
memset(g,0x3f,sizeof g);
while(m--)
{
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
g[a][b] = g[b][a] = min(g[a][b],c);//无向图 使用min是为了去重
}
int t = prim();
if(t == INF) puts("impossible");
else printf("%d\n",t);
return 0;
}
2.AcWing 859. Kruskal算法求最小生成树
考察点:Kruskal算法 适用于稀疏图 并查集
1. 不需要使用邻接矩阵或者邻接表来存图,开一个结构体就好
2.重载<号,使其按照权重大小排序
3.在掌握Kruskal算法前需要复习并查集的相关知识
复习并查集见AcWing相关题目或者看我之前的题解·
具体实现代码如下:
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int N = 100010,M = 200010,INF=0x3f3f3f3f;
int n,m;
int p[N];//并查集
struct Edge //用来存储图
{
int a,b,w;
bool operator<(const Edge &W)const//重载<号,按照权重排序
{
return w<W.w;
}
}edges[M];
int find(int x)//寻找根节点
{
if(p[x]!=x) p[x] = find(p[x]);
return p[x];
}
int kruskal()
{
sort(edges, edges + m);//先快排
for (int i = 1; i <= n; i ++ ) p[i] = i; // 初始化并查集
int res = 0,cnt = 0;//res记录最小生成树的树边权重之和,cnt记录的是全部加入到树的集合中边的数量
for(int i = 0;i<m;i++)//尝试加入每条边
{
int a = edges[i].a,b = edges[i].b,w = edges[i].w;
a = find(a),b = find(b);
if(a!=b)
{
p[a] = b;
res += w;
cnt++;
}
}
if(cnt<n-1) return INF;
else return res;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i = 0;i<m;i++)//建图
{
int a,b,w;
scanf("%d%d%d",&a,&b,&w);
edges[i] = {a,b,w};
}
int t = kruskal();
if(t == INF) puts("impossible");
else printf("%d\n",t);
return 0;
}