【洛谷 3366】最小生成树_Prim
题目描述
如题,给出一个无向图,求出最小生成树,如果该图不连通,则输出orz
输入格式
第一行包含两个整数N、M,表示该图共有N个结点和M条无向边。(N<=5000,M<=200000)
接下来M行每行包含三个整数Xi、Yi、Zi,表示有一条长度为Zi的无向边连接结点Xi、Yi
输出格式
输出包含一个数,即最小生成树的各边的长度之和;如果该图不连通则输出orz
输入输出样例
输入 #1
4 5 1 2 2 1 3 2 1 4 3 2 3 4 3 4 3
输出 #1
7
说明/提示
时空限制:1000ms,128M
数据规模:
对于20%的数据:N<=5,M<=20
对于40%的数据:N<=50,M<=2500
对于70%的数据:N<=500,M<=10000
对于100%的数据:N<=5000,M<=200000
样例解释:
所以最小生成树的总边权为2+2+3=7
题解:Prim算法。分成两个组,在集合里和不在集合里。
然后每次寻找连接两个集合的最近路径,加上即可。类似于Dijkstra
#include<iostream> #include<algorithm> #include<queue> #include<cmath> #include<cstring> #include<cstdlib> #include<cstdio> using namespace std; const int N=400005; const int oo=0x3f3f3f3f; struct node{ int v,w,next; }e[N]; int head[N],dis[N],cnt,n,m; int vis[N],x,y,z,ans; void add(int u,int v,int w){ cnt++; e[cnt].v=v; e[cnt].w=w; e[cnt].next=head[u]; head[u]=cnt; } void boom_JJJ(){ scanf("%d %d",&n,&m); for(int i=1;i<=m;i++){ scanf("%d %d %d",&x,&y,&z); add(x,y,z); add(y,x,z); } for(int i=1;i<=n;i++) dis[i]=oo; } void Yao_Chen_Lai_Le(){ dis[1]=0; //for(int i=2;i<=n;i++) // dis[i]=oo; for(int i=head[1];i;i=e[i].next) dis[e[i].v]=min(dis[e[i].v],e[i].w); int cxk=n-1,now=1; while(cxk--){ int mn=oo; vis[now]=1; for(int i=1;i<=n;i++) if(!vis[i] && mn>dis[i]) { mn=dis[i]; now=i; } ans+=mn; for(int i=head[now];i;i=e[i].next){ int sv=e[i].v; if(dis[sv]>e[i].w && !vis[sv]) dis[sv]=e[i].w; } } } int main(){ freopen("p3366.in","r",stdin); freopen("p3366.out","w",stdout); boom_JJJ(); Yao_Chen_Lai_Le(); printf("%d",ans); return 0; }