最小生成树是一个比较简单数据结构,形成最小生成树的方式有两种。
最小生成树是有图生成树,保证树的每条边的权值之和最小的生成树就叫做最小生成树,这一类的题目起初比较基础,主要是熟悉模板,POJ 1258 也就是这样的题目,非常适合刚刚学习的人。
两种方法的思路分别是找边和找点,简单点说就是,找到全集中最小的边(或者是距离最近的点),将他们连接起来,最终形成的树就是最小生成树。
第一种方法,prim算法,时间复杂度较高不经常使用,是一种找点的方式
这种方式做题的时候最重要的就是要注意,必须注意是不是有一模一样的边,很容易出现类似错误,但是由于不经常使用,这里不多做阐述,以后回单独讲解。
列出模板:
int table[MAXN][MAXN];//用来记录每个点的始点到终点的距离
//例如table[1][2] = 3;表示的是1到2 的距离是3;
//这就是prim的比较差劲的地方,他必须每次都完全遍历寻找
int dis[MAXN];//边的最小距离
int used[MAXN];//标记是否使用过
void prim(){
memset(used,0,sizeof(used));
memset(dis,INF,sizeof(dis));
dis[1] =0;
int sum=0;
while(1){
int smin = INF;
int snt = -1;
//寻找最短的还没有使用过的边
for(int i=1;i<=n;i++){
if(dis[i]<smin&&!used[i]){
smin = dis[i];
snt = i;
}
}
//如果没找到跳出
if(snt==-1)
break;
//找到最小的,也就是最终的边,所以就可以加进去了
sum+=smin;
used[snt] = 1;///标记已使用
//用该边对于所有边进行松弛操作(也就是小则替换)
for(int i=1;i<=n;i++){
if(table[snt][i]!=INF&&dis[i]>table[snt][i]){
dis[i] = table[snt][i];
}
}
}
printf("%d\n",sum);
}
这个题目就是 一个套入模板的板子题,下面是这个题的解答
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<math.h>
#include<stack>
#include<queue>
#include<algorithm>
#define MAXN 105
#define INF 0x3f3f3f3f
using namespace std;
int n;
int table[MAXN][MAXN];
int dis[MAXN];
int used[MAXN];
void prim(){
memset(used,0,sizeof(used));
memset(dis,INF,sizeof(dis));
dis[1] =0;
int sum=0;
while(1){
int smin = INF;
int snt = -1;
for(int i=1;i<=n;i++){
if(dis[i]<smin&&!used[i]){
smin = dis[i];
snt = i;
}
}
if(snt==-1)
break;
sum+=smin;
used[snt] = 1;
for(int i=1;i<=n;i++){
if(table[snt][i]!=INF&&dis[i]>table[snt][i]){
dis[i] = table[snt][i];
}
}
}
printf("%d\n",sum);
}
int main()
{
while(~scanf("%d",&n)){
memset(table,INF,sizeof(table));
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
scanf("%d",&table[i][j]);
}
}
prim();
}
return 0;
}
第二种方法 kruskal算法,是一种找边的思想
大体思路就是,通过寻找不是同一个树上的最短的边,将他们合在同一个树上形成最小生成树。在这个题目上应用,并不是太明显,这个题数据量太小
详细的就看代码注释吧!主要是应用了并查集,https://blog.csdn.net/weixin_40488730/article/details/81586804
如果没有接触过并查集,可以看一下,再回来看下面的代码
#include <cstdio>
#include <algorithm>
#include<cstring>
#include<iostream>
using namespace std;
const int maxn = 105;
struct edge{
int u, v, w;
bool operator < (const edge & p) const {
return w < p.w;
}
} edges[maxn*maxn];
int p[maxn];
int n;
//并查集的查找函数,带有压缩路径
int _find(int x){
if(x!=p[x])
{
p[x] = _find(p[x]);
}
return p[x];
}
int kruskal(){
int ans = 0;
int t=n*n, u, v;
for (int i=n; i<t; ++i){
u = _find(edges[i].u);
v = _find(edges[i].v);
if (u != v){
ans += edges[i].w;
p[u] = v;
}
}
return ans;
}
int main(){
while (scanf("%d", &n)!=EOF){
for (int i=0; i<n; ++i)
p[i] = i;
int w, cnt=0;
for (int i=0; i<n; ++i)
for (int j=0; j<n; ++j){
scanf("%d", &w);
edges[cnt].u = i;
edges[cnt].v = j;
edges[cnt++].w = w;
}
sort(edges, edges+n*n);
printf("%d\n", kruskal());
}
return 0;
}