KOBOSP

导航

经典问题----最小生成树(prim普里姆贪心算法)

题目简述:假如有一个无向连通图,有n个顶点,有许多(带有权值即长度)边,让你用在其中选n-1条边把这n个顶点连起来,不漏掉任何一个点,然后这n-1条边的权值总和最小,就是最小生成树了,注意,不可绕成圈。

思路简介:对比普里姆和克鲁斯卡尔算法,克鲁斯卡尔算法主要针对边来展开,边数少时效率比较高,所以对于稀疏图有较大的优势;而普里姆算法对于稠密图,即边数非常多的情况下更好一些。其大致思路为在现有顶点中任意寻找一个顶点,将他作为根结点,然后在与他连接的所有边中,选择一条最短的边,同时将这条边两端的顶点做上标记,接着搜索所有连接做上标记的两个顶点的边,在除去已经使用过的边中寻找最短的边,如果有相同长度的不同边,则任选一条,接着搜索连接3点的边,重复以上过程。

简单代码:

#include <iostream>  
#include <cmath>  
#include<stdio.h>
#include <cstdio>  
#include <cstring>  
#include<algorithm>  
#include<time.h>
using namespace std;
#define Maxn 110  
#define INF 9999999  
int maz[Maxn][Maxn], lowcase[Maxn], flag[Maxn];
//maz[i][j]表示i到j的距离,注意无向图和重边!lowcase数组存的是现已在树里的点所能到达的点的最小权值  
//flag数组是用来标记某个点是否已经在树里面  
int prim(int n)
{
    int i, j, ans = 0, pos, min;//ans为最小生成树权重,pos为现有边的另一个顶点,mi为当前边的值
    memset(flag, 0, sizeof(flag));//设置所有的顶点为未访问,即0
    for (i = 2; i <= n; ++i)
        lowcase[i] = maz[1][i];//先以1作为根节点,更新lowcase数组  
    lowcase[1] = 0;//为了数组里的值全  
    flag[1] = 1;//1这个点标记为已在树里面,防止绕成圈 
    for (i = 0; i < n - 1; ++i)//循环n-1次,每次找一个点纳入到树里面,加上1根节点总共就是n个点  
    {
        min = INF;//mi为每次在lowcase数组里找到的最小值,所以刚开始赋值成最大值 ,
        //inf一般是因为得到的数值,超出浮点数的表示范围(溢出,即阶码部分超过其能表示的最大值);而nan一般是因为对浮点数进行了未定义的操作,如对-1开方。
        for (j = 1; j <= n; ++j)
        {
            if (!flag[j] && lowcase[j] < min)//未重复   边较小
            {
                min = lowcase[j];
                pos = j;//记录另一端顶点
            }
        }
        ans += min;
        flag[pos] = 1;//标记这一步确定好的顶点
        for (j = 1; j <= n; ++j)//用新的节点更新lowcase数组  
        {
            if (!flag[j] && maz[pos][j] < lowcase[j])
            {
                lowcase[j] = maz[pos][j];
            }
        }
    }
    return ans;
}
int main()
{
    int n, i, j;
    while (~scanf("%d", &n) && n)//输入有几个顶点
    {
        for (i = 1; i <= n; ++i)//构建无向邻接矩阵
        {
            for (j = 1; j <= n; ++j)
                maz[i][j] = i == j ? 0 : INF;
        }//刚开始得把数组里的数存成无穷大 ,那样后期就只需改存在边的数值
        int a, b, c;//a,b为边起始,结束点,c为边长度
        for (i = 0; i < n*(n - 1) / 2; ++i)
        {
            scanf("%d%d%d", &a, &b, &c);
            if (c < maz[a][b])//确保输入边有效
                maz[a][b] = maz[b][a] = c;//无向图+重边  
        }
        int ans = prim(n);
        printf("%d\n", ans);
    }
    return 0;
}

 

posted on 2018-02-04 23:22  KOBOSP  阅读(382)  评论(0)    收藏  举报