POJ 1251 (最小生成树)

本文详细介绍了两种经典的最小生成树算法——Prim算法和Kruskal算法。Prim算法通过不断选择与已选节点相连的最短边来扩展生成树,而Kruskal算法则通过不断选择最小权重的边来构建生成树,同时避免形成环路。

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

很明显,这是一道 最小生成树的例子。也就是,从图中选取若干条边将所有顶点连接起来,并且所选取的这些边的权值之和最小。

算法:Prim算法,或者 Kruskal算法

Prim算法: 首先选择一个点为起点,然后找到与该边相邻权值最小的边,选中该边上的另一个点,然后选择 与选中点  相连接的最小边,这样循环下去,直到包含所有节点

用d[i]表示  与 i 点相邻的最短边的权值,这点是与 Dijkstra算法唯一的不同点

#include <iostream>
using namespace std;

#define MAXV 30
#define MAX 1<<29

int n;
int map[MAXV][MAXV];
int d[MAXV];
bool vis[MAXV];

void prim(){
    int i,j;
    int k = 0;
    for(i=0;i<n;i++){
        vis[i] = 0;
        d[i] = map[0][i];
    }
    for(i=1;i<=n;i++){
        int temp = MAX;
        for(j=0;j<n;j++){
            if(!vis[j]&&d[j]<temp){
                temp = d[j];
                k = j;
            }
        }
        vis[k] = 1;
        for(j=0;j<n;j++){
            if(!vis[j]&&d[j]>map[k][j])
                d[j] = map[k][j];
        }
    }
    for(i=0;i<n;i++)
        d[0] += d[i];
    cout<<d[0]<<endl;
}

int main(){
    int i,j,num,weight;
    char a[2],b[2];
    while(cin>>n,n){
        for(i=0;i<=n;i++)
            for(j=0;j<=n;j++)
                if(i == j)
                    map[i][j] = 0;
                else
                    map[i][j] = MAX;
        for(i=1;i<n;i++){
            cin>>a>>num;
            for(j=1;j<=num;j++){
                cin>>b>>weight;
                map[a[0]-'A'][b[0]-'A'] = map[b[0]-'A'][a[0]-'A'] = weight;
            }
        }
        prim();
    }
    return 0;
}

Kruskal算法是另一种求解最小生成树的经典解法

算法思想:

不断地选择图中权值最小的边,前提是 不能构成回路。

#include <iostream>
#include <algorithm>
using namespace std;

#define INF 1<<29
int p[27];

struct pro{
    int u;
    int v;
    int w;
}map[80];

bool cmp(pro a,pro b){
    return a.w<b.w;
}
int find(int a){
    return a == p[a]?a:a=find(p[a]);
}

int main(){
    int n;
    int i,j,num,c;
    char a[2],b[2];
    while(cin>>n,n){
        int k = 0;
        for(i=0;i<27;i++)
            p[i] = i;
        for(i=0;i<n-1;i++){
            cin>>a>>num;
            for(j=1;j<=num;j++,k++){
                cin>>b>>c;
                map[k].u = a[0] - 'A';
                map[k].v = b[0] - 'A';
                map[k].w = c;
            }
        }
        sort(map,map+k,cmp);
        int ans = 0;
        for(i=0;i<k;i++){
            int x = find(map[i].u);
            int y = find(map[i].v);
            if(x!=y){
                ans += map[i].w;
                p[x] = y;
            }
        }
        cout<<ans<<endl;
    }
    return 0;
}

这个算法 关键是 如何判断 是否有环,方法是 利用 并查集。


总结:Prim算法更注重 点的关系;而Kruskal算法更注重 边的关系


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值