题目描述
如题,给出一个无向图,求出最小生成树,如果该图不连通,则输出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
#include<bits/stdc++.h>
#include<cstring>
#include<queue>
using namespace std;
int vis[10001],dis[10001],head[10001];
int a,b,c,k,cnt,i,n,m,ans;
/*
<1> vis(visted)数组用来标记该点是否在生成树当中
<2> dis(distance)数组用来记录该点到生成树的(现阶段)最小距离
<3> head数组用来记录以该点为起点的当前边的下标,若为-1,则说
明没有以该点为起点的边
*/
struct Edge
{
int len_edge; //记录边的长度
int point_sec; //记录边的终点
int next_edge; //记录同一顶点的前一个边的下标
}e[400001];
void add_edge(int x,int y,int z)
{
e[++k].point_sec=y; //每次存边前,下标自增
e[k].len_edge=z;
e[k].next_edge=head[x]; //将同一顶点的前一个边的下标存进来
head[x]=k; //用当前边的下标更新该顶点所指向的边
}
/*
<1> 我们构建一个整型的二元组合用来记录当前边的长度和终点
<2> 优先队列定义时的三个参数,变量,容器,升序(降序)
*/
typedef pair<int,int> pii;
priority_queue< pii,vector<pii>,greater<pii> > q;
void prim()
{
dis[1]=0; //将起点归入树中,故距离树的距离为0
q.push(make_pair(0,1));
/*
当队列为空时或者cnt==n时退出循环
<1> 单纯第一种情况退出是因为存在点没有连通
<2> 单纯第二种情况退出是因为所有点已经连通,已经生成最小树
*/
while(!q.empty()&&cnt<n)
{
int len=q.top().first,point=q.top().second;
q.pop(); //一定要记得将其pop掉
/*
取出权值最小的边,然后判断该边的终点是否已经被访问过,
也就是已经在生成树中,若已经在生成树中,就直接continue
如果没被访问过,那么cnt++(生成树中已有结点+1),并且将
该点标记为访问过,生成树的(当前)权值也应加上该边的权值
*/
if(vis[point])
continue;
cnt++;
vis[point]=1;
ans+=len;
/*
从当前点为起点最后一个边的下标开始找,e[下标].next_edge
就是以该点为起点的前一个边,直到next_edge的值为-1,说明
前面没有以该点为起点的边了
*/
for(int i=head[point];i!=-1;i=e[i].next_edge)
{
/*
如果以该点为起点的边的权值小于终点到树的距离,那么以此权值
来更新该终点到树的距离,并且将其压入队列当中,相当于用
以此点为起点的边的权值来更新各终点到树的距离
*/
if(e[i].len_edge<dis[e[i].point_sec])
{
dis[e[i].point_sec]=e[i].len_edge;
q.push(make_pair(e[i].len_edge,e[i].point_sec));
}
}
}
}
int main()
{
/*
<1> 将每个结点到生成树的权值初始化为无穷大
<2> 将以每个点为起点的当前边的下标赋值为-1,
也就是说没有以当前点为起点的边了
*/
memset(dis,127,sizeof(dis));
memset(head,-1,sizeof(head));
scanf("%d%d",&n,&m);
for(i=1;i<=m;i++)
{
scanf("%d%d%d",&a,&b,&c);
add_edge(a,b,c); //注意无向图要存两个方向的边
add_edge(b,a,c);
}
prim();
if(cnt==n)
printf("%d\n",ans);
else
printf("orz\n");
return 0;
}