题目描述
如题,给出一个无向图,求出最小生成树,如果该图不连通,则输出 orz
。
输入格式
第一行包含两个整数N,M,表示该图共有 N 个结点和 M 条无向边。
接下来 M 行每行包含三个整数 Xi,Yi,Zi,表示有一条长度为 Zi 的无向边连接结点 Xi,Yi。
输出格式
如果该图连通,则输出一个整数表示最小生成树的各边的长度之和。如果该图不连通则输出 orz
。
输入
4 5
1 2 2
1 3 2
1 4 3
2 3 4
3 4 3
输出
7
#include <stdio.h>
#include <algorithm>
#include <queue>
#include <utility>
using namespace std;
typedef pair<int, int> p; //first为距离,second为顶点编号(因为要放在优先队列中,所以设置为此顺序)
const int maxv = 5004;
const int maxe = 400005;
int dis[maxv] = { 100000000 }; //距离数组
bool vis[maxv] = { false }; //访问数组
int head[maxv] = { -1 }; //起点数组
priority_queue<p, vector<p>, greater<p> > q;
struct edge {
int v; //边的终点
int cost; //边的权重
int next; //同起点的边在数组中的位置
}e[maxe];
int N, M; //顶点数、边数
int cnt; //记录生成树中的顶点数
int k; //记录边数组的下标
void add(int u, int v, int cost) //u为边的起点,v为边的终点,cost为边的权重
{
k++;
e[k].v = v;
e[k].cost = cost;
e[k].next = head[u];
head[u] = k;
}
//顶点编号为从1到n
int ans = 0; //保存结果
void prim()
{
dis[1] = 0;
q.push(make_pair(0, 1)); //从1号顶点开始
while (!q.empty() && cnt < N)
{
int d = q.top().first; //获得距离
int u = q.top().second; //获得距离最近的顶点编号
q.pop();
if (vis[u] == true) //已访问过
continue;
cnt++;
ans += d;
vis[u] = true;
for (int i = head[u]; i != -1; i = e[i].next)
{
//由于使用了优先队列进行排序,所以在探索的时候,得到更小值就更新dis数组,并放入优先队列
if (dis[e[i].v] > e[i].cost)
{
dis[e[i].v] = e[i].cost;
q.push(make_pair(e[i].cost, e[i].v));
}
}
}
}
int main(void)
{
scanf("%d %d", &N, &M);
fill(dis + 1, dis + 1 + N, 1000000);
fill(vis + 1, vis + 1 + N, false);
fill(head + 1, head + 1 + N, -1);
int u, v, cost;
for (int i = 1; i <= M; i++)
{
scanf("%d %d %d", &u, &v, &cost);
add(u, v, cost);
add(v, u, cost);
}
prim();
if (cnt == N)
printf("%d", ans);
else
printf("orz");
}