题目描述
如题,给出一个无向图,求出最小生成树,如果该图不连通,则输出
orz
。输入格式
第一行包含两个整数 �,�N,M,表示该图共有 �N 个结点和 �M 条无向边。
接下来 �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说明/提示
数据规模:
对于 20%20% 的数据,�≤5N≤5,�≤20M≤20。
对于 40%40% 的数据,�≤50N≤50,�≤2500M≤2500。
对于 70%70% 的数据,�≤500N≤500,�≤104M≤104。
对于 100%100% 的数据:1≤�≤50001≤N≤5000,1≤�≤2×1051≤M≤2×105,1≤��≤1041≤Zi≤104。
样例解释:
所以最小生成树的总边权为 2+2+3=72+2+3=7。
1.这是一个最小生成树的算法,我们可以使用 kruskal算法或者prim算法,我这里使用的是kruskal算法。
2.这个算法的核心思想是先排序,排升序。
然后在升序的权值中每次选择最小的,去看是否在已有节点的集合中。
如果已经有了,就不需要,如果没有就需要,继而记录最小生成树的节点个数需要加1,到了n个节点之后,说明已经构成了最小生成树。跳出循环,输出最小值sum。
(这里可以看这篇:2023/1/4总结_lxh0113的博客-CSDN博客)
3.kruskal算法借助了并查集的思想,先设立它的最小生成树的节点已经有1个,因为刚开始的时候俩个节点合并的话,是算他们俩个的,所以初始值为1.
C 代码如下:
#include<stdio.h>
#define N 5010
#define M 200010
struct node
{
int u,v,w;
}edges[M];
int b[N],n,m;
int getf(int x)
{
if(b[x]==x) return x;
b[x]=getf(b[x]);
}
int pd(int x,int y)
{
int p,q;
p=getf(b[x]);
q=getf(b[y]);
if(p!=q)
{
b[q]=p;
return 1;
}
else return 0;
}
int quicksort(int left,int right)
{
if(left>=right) return 0;
int i=left,j=right;
struct node t,temp=edges[left];
while(i<j)
{
while(i<j&&temp.w<=edges[j].w) j--;
while(i<j&&temp.w>=edges[i].w) i++;
if(i<j)
{
t=edges[i];edges[i]=edges[j];edges[j]=t;
}
}
edges[left]=edges[i];
edges[i]=temp;
quicksort(left,i-1);
quicksort(i+1,right);
}
int kruskal()
{
int i,j,sum=0;
for(i=0,j=1;i<m;i++)
{
if(pd(edges[i].u,edges[i].v)==1)
{
j++;
sum+=edges[i].w;
// printf("%d %d \n",edges[i].u,edges[i].v);
}
if(j>=n) break;
}
if(i>=m) return -1;
return sum;
}
int main()
{
int i,j,k;
scanf("%d%d",&n,&m);
for(i=1;i<=n;i++)
b[i]=i;
for(i=0;i<m;i++)
{
scanf("%d%d%d",&edges[i].u,&edges[i].v,&edges[i].w);
}
quicksort(0,m-1);
k=kruskal();
if(k==-1) printf("orz\n");
else printf("%d\n",k);
return 0;
}
C++代码如下:
#include<algorithm>
#include<iostream>
#include<bits/stdc++.h>
using namespace std;
const int N = 5010;
const int M = 200010;
struct node
{
int u, v, w;
} edges[M];
int b[N], n, m;
int getf(int x)
{
if (b[x] == x) return x;
b[x] = getf(b[x]);
}
int pd(int x, int y)
{
int p, q;
p = getf(b[x]);
q = getf(b[y]);
if (p != q)
{
b[q] = p;
return 1;
} else return 0;
}
bool cmp(node a, node b)
{
return a.w < b.w;
}
int kruskal()
{
int i, j, sum = 0;
for (i = 0, j = 1; i < m; i++)
{
if (pd(edges[i].u, edges[i].v) == 1)
{
j++;
sum += edges[i].w;
}
if (j >= n) break;
}
if (i >= m) return -1;
return sum;
}
int main()
{
int i, j, k;
cin >> n >> m;
for (i = 1; i <= n; i++)
b[i] = i;
for (i = 0; i < m; i++)
{
cin >> edges[i].u >> edges[i].v >> edges[i].w ;
}
sort(edges, edges + m - 1, cmp);
k = kruskal();
if (k == -1) cout << "orz" << endl;
else cout << k << endl;
return 0;
}