今天学习的是最小生成树:
生成树:
只要能连通所有顶点而又不产生回路的任何子图都是它的生成树
连接图中所有的点n,并且只有n-1条边的子图就是它的生成树
最小生成树:在生成树中,我们称生成树各边权值和为该树的权。对于无向连通图来说,权值最小的生成树被成为最小生成树。
两种算法:
prim (普里姆算法):
① 先建立一个只有一个结点的树,这个结点可以是原图中任 意的一个结点。
② 使用一条边扩展这个树,要求这条边一个顶点在树中另一 个顶点不在树中,并且这条边的权值要求最小。
③ 重复步骤②直到所有顶点都在树中。
kruskal (克鲁斯卡尔算法)
利用并查集来求最小生成树的算法
题目描述
如题,给出一个无向图,求出最小生成树,如果该图不连通,则输出 orz。
输入格式
第一行包含两个整数 N,MN,M,表示该图共有 NN 个结点和 MM 条无向边。
接下来 MM 行每行包含三个整数 X_i,Y_i,Z_iX
i
,Y
i
,Z
i
,表示有一条长度为 Z_iZ
i
的无向边连接结点 X_i,Y_iX
i
,Y
i
。
输出格式
如果该图连通,则输出一个整数表示最小生成树的各边的长度之和。如果该图不连通则输出 orz。
输入输出样例
输入 #1复制
4 5
1 2 2
1 3 2
1 4 3
2 3 4
3 4 3
输出 #1复制
题解:就是模板题目,考察最小生成树的写法,因为学过了并查集,所以克鲁斯卡尔算法理解的更快,就采用了克鲁斯卡尔算法。
#include
#include
#include
#include
int n,m;
long long int sum;
int f[200005];
struct node
{
int x;
int y;
int z;
} a[200005];
int find(int x)//并查集查找
{
if(x==f[x])
return x;
else
return find(f[x]);
}
int cmp(const void*a,const void*b)//结构体排序
{
struct node aa=*(struct node*)a;
struct node bb=*(struct node*)b;
return aa.z>bb.z?1:-1;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=0; i1)
printf("orz\n");
else
printf("%lld\n",sum);
return 0;
}
还记得 NOIP 2011 提高组 Day1 中的铺地毯吗?时光飞逝,光阴荏苒,三年过去了。组织者精心准备的颁奖典礼早已结束,留下的则是被人们踩过的地毯。请你来解决类似于铺地毯的另一个问题。
题目描述
会场上有 n 个关键区域,不同的关键区域由 m 条无向地毯彼此连接。每条地毯可由三个整数 u、v、w 表示,其中 u 和 v 为地毯连接的两个关键区域编号,w 为这条地毯的美丽度。
由于颁奖典礼已经结束,铺过的地毯不得不拆除。为了贯彻勤俭节约的原则,组织者被要求只能保留 K 条地毯,且保留的地毯构成的图中,任意可互相到达的两点间只能有一种方式互相到达。换言之,组织者要求新图中不能有环。现在组织者求助你,想请你帮忙算出这 K 条地毯的美丽度之和最大为多少。
输入格式
第一行包含三个正整数 n、m、K。
接下来 m 行中每行包含三个正整数 u、v、w。
输出格式
只包含一个正整数,表示这 K 条地毯的美丽度之和的最大值。
输入输出样例
输入 #1复制
5 4 3
1 2 10
1 3 9
2 3 7
4 5 3
输出 #1复制
22
题解:
1.表明要将多条红毯铺成一条,即就是合并,所以确定使用克鲁斯卡尔算法。
2.结束条件,红毯只要k条,所以需要一个计数器,当达到所需要的红毯数的时候就需要结束循环
3.题目求最大权值,所以排序要降序
#include
#include
int n,m,k;
int cnt=0;
int f[200005];
long long int sum;
struct node
{
int x;
int y;
int z;
} a[200005];
int find(int x)//并查集查找
{
if(x==f[x])
return x;
else
return find(f[x]);
}
int cmp(const void*a,const void*b)
{
struct node aa=*(struct node*)a;
struct node bb=*(struct node*)b;
return aa.z>bb.z?-1:1;//降序
}
int main()
{
scanf("%d%d%d",&n,&m,&k);
for(int i=1; i<=n; i++)//初始化
f[i]=i;
for(int i=1; i<=m; i++)
scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].z);
qsort(a+1,m,sizeof(a[1]),cmp);//降序排序
for(int i=1; i<=m; i++)
{
int x=find(a[i].x);
int y=find(a[i].y);
if(x==y)
continue;
sum+=a[i].z;//权值相加
f[y]=x;
cnt++;
if(cnt==k)//合并的红毯数已经达到题目给出的红毯数
break;
}
printf("%lld\n",sum);
return 0;
}