最小生成树两种算法。kruskal和prim

本文详细介绍了图论中的两种经典最小生成树算法——Kruskal算法与Prim算法。Kruskal算法通过将所有边按长度排序后逐一检查是否形成环来构建最小生成树;Prim算法则类似Dijkstra算法,从一个顶点出发逐步扩展树的边界。两种算法各有优劣,适用于不同的场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

测试数据:
8
0 2 8 1 0 0 0 0
2 0 6 0 1 0 0 0
8 6 0 7 5 1 2 0
1 0 7 0 0 0 9 0
0 1 5 0 0 3 0 8
0 0 1 0 3 0 4 6
0 0 2 9 0 4 0 3
0 0 0 0 8 6 3 0

8个点,矩阵m[i][j]代表i与j的距离。
kruskal
所有边按长度从小到大排序,如果边的两点连在一起,那么就不添加边,如果不连在一起,就添加边。用并查集维护是否连在一起。

/***********************************************\
 |Author: YMC
 |Created Time: 2014-5-9 18:25:59
 |File Name: kruskal.cpp
 |Description: 
\***********************************************/
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <string>
#include <cstring>
#include <algorithm>
#include <vector>
#include <list>
#include <map>
#include <set>
#include <deque>
#include <queue>
#include <stack>
using namespace std;
#define N 100
#define inf 1<<29
struct seg{
    int x,y,c;
}se[1000];
int n;
int ma[N][N];
int fa[N];
int cnt;
void init(int n){
    for(int i=1;i<=n;++i) fa[i] = i;
}
int find(int x){
    return fa[x] = fa[x] == x ? x : find(fa[x]);        //路径优化,可以使查询速度稳定在O(n) 
}
void merge(int x,int y){
    int a = find(x);
    int b = find(y);
    fa[a] = b;
}
bool judge(int x,int y){
    if(find(x) == find(y)) return true;
    else return false;
}
bool cmp(seg a,seg b){
    return a.c < b.c;
}
int kruskal()
{
    sort(se,se+cnt,cmp);    //边排序 
    init(n);        //并查集初始化 
    int cas = 0;
    int ans = 0;
    for(int i=0;i<cnt;++i){
        int x = se[i].x;
        int y = se[i].y;
        int c = se[i].c;
        if(!judge(x,y)){
            //cout<<x<<" "<<y<<endl;
            ans += c;
            cas ++;
            if(cas == n-1) return ans;
        }
    }
}
int main() {
    freopen("input.txt","r",stdin);
    scanf("%d",&n);
    cnt = 0; 
    for(int i=1;i<=n;++i){          //输入 
        for(int j=1;j<=n;++j)
        {
            scanf("%d",&ma[i][j]);
            if(ma[i][j] == 0) ma[i][j] = inf;
        }
    }
    for(int i=1;i<n;++i){       //放入边 
        for(int j=i+1;j<=n;++j){
            seg tp;
            tp.x = i;
            tp.y = j;
            tp.c = ma[i][j];
            se[cnt ++] = tp;
        }
    }
    printf("%d\n",kruskal());       //输出最小生成树长度 
    return 0;

}

prim
类似dijstra,从一个点开始找,每次找到与当前连在一起的点的最短的距离的那个点,然后添加那条当前最短的边。

/***********************************************\
 |Author: YMC
 |Created Time: 2014-5-9 18:13:44
 |File Name: prim.cpp
 |Description: 
\***********************************************/
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <string>
#include <cstring>
#include <algorithm>
#include <vector>
#include <list>
#include <map>
#include <set>
#include <deque>
#include <queue>
#include <stack>

using namespace std;
#define N 100
#define inf 1<<29
int n;
int ma[N][N];
int dis[N];
bool vis[N];
int prim()
{
    for(int i=1;i<=n;++i) dis[i] = inf;
    memset(vis,false,sizeof(vis));
    dis[1] = 0;
    vis[1] = true;
    for(int i=2;i<=n;++i) dis[i] = ma[1][i];
    int ans = 0;
    for(int ii = 2;ii<=n;++ii){
        int minn = inf;
        int pos = -1;
        for(int i=2;i<=n;++i){
            if(!vis[i] && minn > dis[i]){
                minn = dis[i];
                pos = i;
             }
        }
        dis[pos] = minn;
        vis[pos] = true;
        ans += minn;
        for(int i=1;i<=n;++i){
            if(!vis[i] && dis[i]>ma[pos][i]){
                dis[i] = ma[pos][i];
            }
        }
    }
    return ans;
}
int main() {
    freopen("input.txt","r",stdin);
    scanf("%d",&n); 
    for(int i=1;i<=n;++i){
        for(int j=1;j<=n;++j)
        {
            scanf("%d",&ma[i][j]);
            if(ma[i][j] == 0) ma[i][j] = inf;
        }
    }
    printf("%d\n",prim());
    return 0;

}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值