最小生成树MST : poj 1258 Agri-Net+hdu 1102 Constructing Roads

最小生成树的两种算法

这里写图片描述

  • 定义:对于有权值的无向图来说,其边权值最小的生成树称作图G的最小生成树。
  • 求解最小生成树(Minimum Spanning Tree,简称MST)是图相关算法中常见的一个,用于解决类似如下的问题:
    假设要在N个城市之间建立通信联络网,那么连通N个城市只需N-1条线路。这时自然会考虑这样一个问题:如何在最节省经费的前提下建立这个通信网。
    在任意两个城市间都可以设置一条线路,相应地都要付出一定的经济代价。N个城市之间最多可能设置N(N-1)/2条线路,那么如何在这些线路中选择N-1条,以使总的耗费最少呢?
    可以用连通图来表示N个城市,顶点表示城市,通信线路就是带有权值的边。一般而言,一个连通图有多个生成树,这些生成树的总的权值不同,其中会有1或多个的总权值最小,这1或多个生成树就是我们要求解的MST。(只需求出其中一个即可)
    本篇介绍两种求解MST的算法:Prim和Kruskal,

这里写图片描述
将图G中的所有顶点分为两个顶点集合U和V。
Prim算法的思路:初始时随便取一个顶点vertex(通常选第一个)作为U,其它顶点作为V。这时,只含有1个顶点的U,其MST-U就是vertex本身,这是已知的。(已经符合假设了)而V范围内的连接方式尚属未知。我们已经可以求得连接MST-U和MST-V的那条边u-v,顺着u-v,就可以把V中的顶点v拉到U里边。这样重复地拉取顶点,直到V中没有顶点时,U就覆盖了整个G,我们就求得了整个G的MST!

具体步骤:
- 首先初始化,生成树的总权值为0,任选一个顶点(通常第一个)放入U,其余的放入V.
- 在所有属于V的点中找到v,U中找到一点u,使u到v的边的权值最小,将v从V中除去,加入到U中,并将该边的边权值加入到生成树的总权值中,标记这条边.
- 重复上一步骤,直到V中没有点或者V中的点与U中的点没有边链接.

最小生成树Prim算法实现:

http://www.cnblogs.com/Veegin/archive/2011/04/29/2032388.html

这里写图片描述

裸求最小生成树,prim算法.

参考代码+部分注释

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <map>
#include <vector>
#include <queue>
#include <cstring>
#include <cmath>
#include <climits>
#define eps 1e-8
using namespace std;
typedef long long ll;
const int INF=INT_MAX;
const int maxn = 110;
int n;
int edge[maxn][maxn];//邻接矩阵
int low[maxn];//low数组记录U集合与其他各点的最小权值
bool visited[maxn];//标记数组
int prim()//普里姆算法求解最小生成树MST
{
    int ans=0;
    //从第一个点开始,数据初始化过程
    memset(visited,false,sizeof(visited));
    int pos=1;
    visited[1]=true;
    for(int i=1;i<=n;i++)
        low[i]=(i==1?0:edge[1][i]);
    for(int i=1;i<n;i++){//循环n-1次,每次循环加入一个点
       int min=INF;
       for(int j=1;j<=n;j++) //遍历所有的点,找出最小权值min并记录该位置
       if(visited[j]==false&&low[j]<min){
        min=low[j];
        pos=j;
       }
       if(min==INF) return -1;//原图不连通
       ans+=min;//累加最小权值
       visited[pos]=true;//标记pos该点
       for(int j=1;j<=n;j++)//遍历所有的点,更新low[]数组
       if(visited[j]==false&&edge[pos][j]<low[j]){
         low[j]=edge[pos][j];
       }
    }
    return ans;
}
int main()
{
   //freopen("input.txt","r",stdin);
   int temp;
   while(cin>>n){
    for(int i=1;i<=n;i++)  //存储邻接表
    for(int j=1;j<=n;j++){
        cin>>temp;
        edge[i][j]=temp;
    }
    cout<<prim()<<endl;
   }
   return 0;
}

这里写图片描述

prim算法实现,注意读入数据时已经建好的城市之间的距离置为0.

参考代码+部分解释

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <map>
#include <vector>
#include <queue>
#include <cstring>
#include <cmath>
#include <climits>
#define eps 1e-8
using namespace std;
typedef long long ll;
const int INF=INT_MAX;
const int maxn = 110;
int n;
int edge[maxn][maxn];//邻接矩阵
int low[maxn];//low数组记录Va集合与其他各点的最小权值
bool visited[maxn];//标记数组
int prim()//普里姆算法求解最小生成树MST
{
    int ans=0;
    //从第一个点开始,数据初始化过程
    memset(visited,false,sizeof(visited));
    int pos=1;
    visited[1]=true;
    for(int i=1;i<=n;i++)
        low[i]=(i==1?0:edge[1][i]);
    for(int i=1;i<n;i++){//循环n-1次,每次循环加入一个点
       int min=INF;
       for(int j=1;j<=n;j++) //遍历所有的点,找出最小权值min并记录该位置
       if(visited[j]==false&&low[j]<min){
        min=low[j];
        pos=j;
       }
       if(min==INF) return -1;//原图不连通
       ans+=min;//累加最小权值
       visited[pos]=true;//标记pos该点
       for(int j=1;j<=n;j++)//遍历所有的点,更新low[]数组
       if(visited[j]==false&&edge[pos][j]<low[j]){
         low[j]=edge[pos][j];
       }
    }
    return ans;
}
int main()
{
  // freopen("input.txt","r",stdin);
   while(cin>>n){
    for(int i=1;i<=n;i++)  //存储邻接表
    for(int j=1;j<=n;j++){
        cin>>edge[i][j];
    }
    //已经连通的城市之间的距离置为0
    int m;cin>>m;int from,to;
    for(int i=1;i<=m;i++){
       cin>>from>>to;
       edge[from][to]=edge[to][from]=0;
    }
      cout<<prim()<<endl;
    }
   return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值