题目链接
使用的是prim算法,prim算法与最短路径中的Dijkstra算法很相像。一个点一个点进行排查,直到图中的所有点都遍历一遍。
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <string>
#include <map>
#include <queue>
#include <cstring>
#include <cmath>
const int maxn=5005;
const int maxm=200005;
const int inf=123456789;
using namespace std;
int n,m,head[maxm],vis[maxn],num=0,ans=0,dis[maxn],t=0,now=1; //数组head是链式前向星的存储,数组vis是记录每个点的状态:是否已经遍历,数组dis是记录去每个点的最短路径
struct Edge //用结构体存储图,与spfa一样
{
int next,to,dist;
}e[maxm*2];
void addedge(int x,int y,int z) //链式前向星存储方式
{
e[++num].next=head[x];
e[num].to=y;
e[num].dist=z;
head[x]=num;
}
int prim() //prim算法
{
for(int i=1;i<=n;i++){ //将dis初始化为最大(不可通过),在数组vis中0表示没有遍历,1表示已经遍历
dis[i]=inf;
vis[i]=0;
}
dis[1]=0; //从图中的点‘1’开始遍历
for(int i=head[1];i;i=e[i].next){ //先将dis赋值每一个点的dist,防止重边所以用min
dis[e[i].to]=min(dis[e[i].to],e[i].dist);
}
while(++t<n){ //t为所遍历的点数
int minn=inf;
vis[now]=1; //从‘1’开始,所以now初始化为1
for(int i=1;i<=n;i++){
if(!vis[i] && minn>dis[i]){ //查找还没遍历过的点中的最短边,然后用minn记录下来
minn=dis[i];
now=i;
}
}
ans+=minn;
for(int i=head[now];i;i=e[i].next){
int to=e[i].to;
if(dis[to]>e[i].dist && !vis[to])
dis[to]=e[i].dist;
}
}
return ans;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++){
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
addedge(x,y,z);
addedge(y,x,z);
}
printf("%d\n",prim());
return 0;
}