最小生成树 prim

思想:
MST(Minimum Spanning Tree,最小生成树)问题有两种通用的解法,Prim算法就是其中之一,它是从点的方面考虑构建一颗MST,大致思想是:设图G顶点集合为U,首先任意选择图G中的一点作为起始点a,将该点加入集合V,再从集合U-V中找到另一点b使得点b到V中任意一点的权值最小,此时将b点也加入集合V;以此类推,现在的集合V={a,b},再从集合U-V中找到另一点c使得点c到V中任意一点的权值最小,此时将c点加入集合V,直至所有顶点全部被加入V,此时就构建出了一颗MST。因为有N个顶点,所以该MST就有N-1条边,每一次向集合V中加入一个点,就意味着找到一条MST的边。

过程:
http://blog.csdn.net/yeruby/article/details/38615045

这里写图片描述
测试用例:
输入:
6 10
1 2 6
1 3 1
1 4 5
2 3 5
2 5 3
3 4 5
3 5 6
3 6 4
4 6 2
5 6 6
输出:
15

这里写图片描述

# include <iostream>
# include <cstdio>
# include <cstring>
using namespace std;

# define MAXN 1000
# define INF 0x3f3f3f3f//这个可以与memset(数组名,INF,sizeof(数组名));  这样可以对数组的全部元素赋值为最大值 
int map[MAXN][MAXN],lowcost[MAXN];
bool visit[MAXN];
int n,m,sum;//n节点  m边数  sum保存的是一个城市到另一个城市的最小权值 
/*
    map保存的是map[a][b] --->a到b的权值
    lowcost数组保存的是一个城市到其余的城市的最小的权值 
    visit保存的是该节点是否被访问过 
*/
void prim();
int main(){

    int a,b,cost;//a城市到b城市的权值为cost

    while(scanf("%d%d",&n,&m)!=EOF){

        memset(map,INF,sizeof(map));//map的每一个元素初始化为最大值 

        for(int i=1;i<=m;i++){
            scanf("%d%d%d",&a,&b,&cost);
            if(cost < map[a][b])
                map[a][b] = map[b][a] = cost;
        }

        prim(); 
        printf("%d\n",sum);



    }



    return 0;
}


void prim(){

    int temp,k;
    sum = 0;
    memset(visit,false,sizeof(visit));//初始化visit 全部为false  证明该节点没有被访问过 
    visit[1] = true;//说明第一个节点已经被访问过

    for(int i=1;i<=n;i++){//对lowcost初始化 
        lowcost[i] = map[1][i];
    } 

    for(int i=1;i<=n;i++){//找生成树集合点集相连最小权值的边
        temp = INF;
        for(int j=1;j<=n;j++){//检索没有被访问的城市,而且权值最小的那个城市 ,并保存权值 
            if(!visit[j] && temp>lowcost[j]){
                temp = lowcost[k=j];
            }
        }

        if(temp == INF)//该节点与任何节点没有相连, 
            break;

        visit[k] = true;//把这个城市加入最小生成树集合
        sum+=temp; //记录权值之和

        for(int j=1;j<=n;j++){//更新lowcost数组
            if(!visit[j] && lowcost[j]>map[k][j]){
                lowcost[j] = map[k][j];
            }
        }   

    } 

}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值