7-6 最小生成树-prim
目录
题目描述
输入格式:
输出格式:
输入样例:
输出样例:
解题思路:
举个例子:
详细代码:
堆优化的prim详细代码:
题目描述
题目给出一个无向连通图,要求求出其最小生成树的权值。
温馨提示:本题请使用prim最小生成树算法。
输入格式:
第一行包含两个整数 N(1<=N<=1x104),M(1<=M<=2x106) 表示该图共有 N 个结点和 M 条无向边。
接下来 M 行每行包含三个整数 Xi,Yi,Zi ,表示有一条长度为 Zi 的无向边连接结点 Xi,Yi 。
输出格式:
输出一个整数表示最小生成树的各边的长度之和。
输入样例:
4 5 1 2 2 1 3 2 1 4 3 2 3 4 3 4 3
输出样例:
7
解题思路:
思想与dijkstra相同
即从1号点开始,将其纳入集合,查找与其距离最短的边,只需记录该点的终点是否走过,
然后将这条边连接的点也纳入集合中,查找与这个集合距离最短的另一条边,依次进行下去。
举个例子:
根据输入样例
4 5
1 2 2
1 3 2
1 4 3
2 3 4
3 4 3可以构建一个如图所示的无向图
定义最小生成树总权值sum=0
首先将1号点放入集合中,集合{1}
查找与集合1最近的边为1到2的边权值为2,总权值sum=sum+2=2
之后2进入集合{1,2}
查找与集合最近的边为1到3的边权值为2,总权值sum=sum+2=4
之后3进入集合{1,2,3}
查找与集合最近的边为1到4的边权值为3,总权值sum=sum+3=7
构建最小生成树如下图
此时集合中有{1,2,3,4}全都被标记在集合中
详细代码:
#include <iostream> #include <cstring> #include <algorithm> #include <vector> using namespace std; const int N=1e5+7; struct asd{ int x,y; }; vector<asd>ljb[N]; int dist[N];//当前点i到集合的最短距离 int st[N];//等于1在集合中,等于0不在集合中 int n, m; int prim(){ memset(dist,0x3f,sizeof dist); int res=0;//计算生成树最小权值 for (int i=0;i<n;i++) { int t=-1; for (int j=1;j<=n;j++) { if (st[j]==0&&(t==-1||dist[t]>dist[j]))//找到当前离集合最短距离的点 t=j; } if(i) { res+=dist[t]; } st[t]=1; for (int j=0;j<ljb[t].size();j++) { asd ls=ljb[t][j]; dist[ls.x]=min(dist[ls.x],ls.y);//更新点到集合的最短距离 } } return res; } int main() { scanf("%d %d",&n,&m); while(m--){ int a,b,c; scanf("%d %d %d",&a,&b,&c);; ljb[a].push_back({b,c});//邻接表储存边信息 ljb[b].push_back({a,c}); } int t=prim(); printf("%d",t); }
堆优化的prim详细代码:
#include<iostream> #include<vector> #include<queue> #include<cstring> using namespace std; const int N = 1e4+10; typedef pair<int,int> PII;//用PTT替换pair<int,int>文本 vector<PII>ljb[N]; bool vis[N];//记录是否走过 int dis[N]; int n,m; void prim() { memset(dis,0x3f,sizeof dis);//将其他点到集合的距离设为无穷大 dis[1] = 0;//初始化1到集合的距离 int res = 0; priority_queue<PII,vector<PII>,greater<PII>> q;//优先队列,将距离更小的放在前面 q.push({0,1}); while(!q.empty()) { int t = q.top().second;//取出当前出队的点 q.pop(); if(vis[t]) continue;//如果走过即跳过 vis[t] = true;//走了则标记 res += dis[t];//记录最小生成树的权值 for(auto ls:ljb[t])//遍历与t相邻的点的距离 { int k=ls.first,w=ls.second; if(dis[k]>w)//如果之前更新的相邻点的与当前点的距离大于现在更新的距离则替换 { dis[k]=w; q.push({w,k});//将距离和该点入队 } } } printf("%d",res); } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=m;i++) { int u,v,w; scanf("%d%d%d",&u,&v,&w); ljb[u].push_back({v,w});//邻接表存储边信息 ljb[v].push_back({u,w}); } prim(); return 0; }