ACM第四站————最小生成树(普里姆算法)

对于一个带权的无向连通图,其每个生成树所有边上的权值之和可能不同,我们把所有边上权值之和最小的生成树称为图的最小生成树

普里姆算法是以其中某一顶点为起点逐步寻找各个顶点上最小权值的边来构建最小生成树。

其中运用到了回溯,贪心的思想。

废话少说吧,这个其实是一个模板,直接套用就好!直接上题吧!这些东西多练就好!

一、最小生成树:

题目描述

求一个连通无向图的最小生成树的代价(图边权值为正整数)。

输入

第 一行是一个整数N(1<=N<=20),表示有多少个图需要计算。以下有N个图,第i图的第一行是一个整数M(1<=M& lt;=50),表示图的顶点数,第i图的第2行至1+M行为一个M*M的二维矩阵,其元素ai,j表示图的i顶点和j顶点的连接情况,如果 ai,j=0,表示i顶点和j顶点不相连;如果ai,j>0,表示i顶点和j顶点的连接权值。

输出

每个用例,用一行输出对应图的最小生成树的代价。

样例输入

1
6
0 6 1 5 0 0
6 0 5 0 3 0
1 5 0 5 6 4
5 0 5 0 0 2
0 3 6 0 0 6
0 0 4 2 6 0

样例输出

15

//Asimple
#include <stdio.h>
#include <iostream>
#include <string.h>

using namespace std;
#define INF 0xffffff
const int maxn = 55;
int G[maxn][maxn];//建图
int T, n;

int prim()
{
    int Min, sum = 0;
    int adv[maxn]; //保存定点下标
    int lowc[maxn]; //保存权值

    adv[0] = lowc[0] = 0 ;
    //初始化
    for(int i=1; i<n; i++)
    {
        lowc[i] = G[0][i];//先放入 第0行 的所有权值
        adv[i] = 0 ;
    }

    //构建过程
    for(int i=1; i<n; i++)
    {
        Min = INF ;
        int j = 1 ;
        int k = 0 ;

        while( j < n )
        {
            if( lowc[j]!=0 && lowc[j]<Min)
            {
                Min = lowc[j] ;
                k = j ;
            }
            j ++ ;
        }
        sum += G[adv[k]][k] ;//计算最小权值
        //printf("%d,%d",adv[k],k);//打印节点
        lowc[k] = 0 ;

        //逐行遍历接下来的k个顶点
        for(int l=1; l<n; l++)
        {
            if( lowc[l]!=0 && G[k][l] < lowc[l] )
            {
                lowc[l] = G[k][l] ;
                adv[l] = k ;
            }
        }
    }
    return sum ;
}

int main()
{
    cin >> T ;
    while( T -- )
    {
        cin >> n ;
        for(int i=0; i<n; i++)
            for(int j=0; j<n; j++)
            {
                cin >> G[i][j];
                if( G[i][j] == 0 && i!=j )
                    G[i][j] = INF ;
            }
        cout << prim() << endl ;
    }

    return 0;
}

二、判断最小生成树是否唯一

题目描述

给出一个连通无向图,请判断其最小生成树是否是唯一的。

定义1(生成树):给出一个连通无向图G=(V,E),G的一颗生成树被标记为T=(V,E),则具有以下性质:

1)V‘=V;

2)T是连通无回路的。

定义2(最小生成树):给出一个边带权的连通无向图G=(V,E),G 的最小生成树T=(v,E)是具有最小总耗费的生成树。T的总耗费表示E‘ 中所有边的权值的和。

输入

第 一行给出一个整数t(1<=t<=20),表示测试用例数,每个测试用例表示一个图,测试用例的第一行给出两个整数n,m(1<=n<=100),分别表 示顶点和边的数目,后面的m行每行是一个三元组(xi,yi,wi),表示xi和yi通过权值为wi的边相连。任意两个节点间至多只有一条边相连。

输出

对于每个测试用例,如果MST是唯一的,输出其总耗费;否则输出字符串‘Not Unique!‘.

样例输入

2
3 3
1 2 1
2 3 2
3 1 3
4 4
1 2 2
2 3 2
3 4 2
4 1 2

样例输出

3

Not Unique!

#include <stdio.h>
#include <iostream>
#include <string.h>

using namespace std;
#define INF 0xffffff
const int maxn = 55;
int G[maxn][maxn];//建图
int T, n, m, x, y, num;

void prim()
{
    int Min, sum = 0;
    int adv[maxn]; //保存定点下标
    int lowc[maxn]; //保存权值
    bool flag = false ;

    adv[0] = lowc[0] = 0 ;
    //初始化
    for(int i=1; i<n; i++)
    {
        lowc[i] = G[0][i];//先放入 第0行 的所有权值
        adv[i] = 0 ;
    }

    //构建过程
    for(int i=1; i<n; i++)
    {
        Min = INF ;
        int j = 1 ;
        int k = 0 ;

        while( j < n )
        {
            if( lowc[j]!=0 && lowc[j]<=Min)
            {
                if( lowc[j] == Min ) flag = true ;
                Min = lowc[j] ;
                k = j ;
            }
            j ++ ;
        }
        sum += G[adv[k]][k] ;//计算最小权值
        lowc[k] = 0 ;

        //逐行遍历接下来的k个顶点
        for(int l=1; l<n; l++)
        {
            if( lowc[l]!=0 && G[k][l] < lowc[l] )
            {
                lowc[l] = G[k][l] ;
                adv[l] = k ;
            }
        }
    }
    if( flag ) cout << "Not Unique!" << endl ;
    else cout << sum << endl ;
}

int main()
{
    cin >> T ;
    while( T -- )
    {
        cin >> n >> m ;
        for(int i=0; i<n; i++)
            for(int j=0; j<n; j++)
            {
                if( i == j ) G[i][j] = 0 ;
                else G[i][j] = INF ;
            }
        for(int i=0; i<m; i++)
        {
            cin >> x >> y >> num ;
            G[x-1][y-1] = num ;
            G[y-1][x-1] = num ;
        }
        prim();
    }

    return 0;
}

ACM,多看书多做题!

时间: 2024-10-27 13:19:25

ACM第四站————最小生成树(普里姆算法)的相关文章

图-&gt;连通性-&gt;最小生成树(普里姆算法)

文字描述 用连通网来表示n个城市及n个城市间可能设置的通信线路,其中网的顶点表示城市,边表示两城市之间的线路,赋于边的权值表示相应的代价.对于n个定点的连通网可以建立许多不同的生成树,每一棵生成树都可以是一个通信网.现在,我们要选择这样一个生成树,使总的耗费最少.这个问题就是构造连通网的最小代价生成树(Minimum Cost Spanning Tree: 最小生成树)的问题.一棵生成树的代价就是树上各边的代价之和. 有多种算法可以构造最小生成树,其他多数都利用的最小生成的MST(minimum

ACM第四站————最小生成树(克鲁斯卡尔算法)

都是生成最小生成树,库鲁斯卡尔算法与普里姆算法的不同之处在于——库鲁斯卡尔算法的思想是以边为主,找权值最小的边生成最小生成树. 同样的题目:最小生成树 题目描述 求一个连通无向图的最小生成树的代价(图边权值为正整数). 输入 第 一行是一个整数N(1<=N<=20),表示有多少个图需要计算.以下有N个图,第i图的第一行是一个整数M(1<=M& lt;=50),表示图的顶点数,第i图的第2行至1+M行为一个M*M的二维矩阵,其元素ai,j表示图的i顶点和j顶点的连接情况,如果 ai

数据结构之最小生成树(普里姆算法)

1)普里姆算法 可取图中任意一个顶点v作为生成树的根,之后若要往生成树上添加顶点w,则在顶点v和顶点w之间必定存在一条边,并且 该边的权值在所有连通顶点v和w之间的边中取值最小.一般情况下,假设n个顶点分成两个集合:U(包含已落在生成树上 的结点)和V-U(尚未落在生成树上的顶点),则在所有连通U中顶点和V-U中顶点的边中选取权值最小的边. 例如:起始生成树上面就一个顶点.为了连通两个集合,在可选的边中,选择权值最小的.需要辅助数组,V-U中所有顶点. 具体实例如下图所示:求下图的最小生成树 我

数据结构-最小生成树-普里姆算法

转自https://blog.csdn.net/ZGUIZ/article/details/54633115 首先仍然是预定义: 1 #define OK 1 2 #define ERROR 0 3 #define Max_Int 32767 4 #define MVNum 100 5 6 typedef int Status; 7 typedef char VerTexType; 8 typedef int ArcType; 9 10 struct{ 11 VerTexType adjvex;

数据结构(五)图---最小生成树(普里姆算法)

一:最小生成树 (一)定义 我们把构造连通网的最小代价生成树称为最小生成树 (二)什么是最小生成树? 1.是一棵树 1)无回路 2)N个顶点,一定有N-1条边 2.是生成树 1)包含全部顶点 2)N-1条边都在图中 3.边的权重和最小 (三)案例说明 在实际生活中,我们常常碰到类似这种一类问题:如果要在n个城市之间建立通信联络网, 则连通n个城市仅仅须要n-1条线路.这时.我们须要考虑这样一个问题.怎样在最节省经费前提 下建立这个通信网.换句话说,我们须要在这n个城市中找出一个包括全部城市的连通

数据结构例程——最小生成树的普里姆算法

本文是[数据结构基础系列(7):图]中第11课时[最小生成树的普里姆算法]的例程. (程序中graph.h是图存储结构的"算法库"中的头文件,详情请单击链接-) #include <stdio.h> #include <malloc.h> #include "graph.h" void Prim(MGraph g,int v) { int lowcost[MAXV]; //顶点i是否在U中 int min; int closest[MAXV]

46. 蛤蟆的数据结构笔记之四十六普里姆算法

46. 蛤蟆的数据结构笔记之四十六普里姆算法 本篇名言:"手莫伸 ,伸手必被捉.党与人民在监督 ,万目睽睽难逃脱.汝言惧捉手不伸 ,他道不伸能自觉 , 其实想伸不敢伸 ,人民咫尺手自缩.-- 陈毅" 连通图的生成树是一个极小的连通子图,它含有图中全部的顶点,但只有足以构成一棵树的n-1条边.所谓的最小成本,就是n个顶点,用n-1条边把一个连通图连接起来,并且使得权值的和最小.构造连通网的最小代价生成树,即最小生成树(Minimum Cost Spanning Tree). 找连通图的最

普里姆算法-prim

算法代码: C++ Code 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 /* Prim算法生成最小生成树  */ void MiniSpanTree_Prim(MGraph MG) { int min, i, j, k; int adjvex[MAXVEX];/* 

普里姆算法介绍

普里姆(Prim)算法,和克鲁斯卡尔算法一样,是用来求加权连通图的最小生成树的算法. 基本思想 对于图G而言,V是所有顶点的集合:现在,设置两个新的集合U和T,其中U用于存放G的最小生成树中的顶点,T存放G的最小生成树中的边. 从所有u?U,v?(V-U) (V-U表示出去U的所有顶点)的边中选取权值最小的边(u, v),将顶点v加入集合U中,将边(u, v)加入集合T中,如此不断重复,直到U=V为止,最小生成树构造完毕,这时集合T中包含了最小生成树中的所有边. 普里姆算法图解 以上图G4为例,