【贪心】畅通工程系列4-HDU1233 还是畅通工程-Prim算法

题目

http://acm.hdu.edu.cn/showproblem.php?pid=1233

问题分析

本题求是整个省畅通的最低成本,把村庄作为顶点,把公路作为边,那么本题就是求最小生成树的总边权值。

算法

算法核心

本题可采用Prim算法,其实这也是贪心的一种。设V为顶点的全集,U初始化{v0},每次都选择V-U中到分支U最近的点,然后把该点加入U,更新V-U中的点到U的距离,然后再次选择直至U=V。

算法流程

closest[]:V-U中的点到分支U的最近的点;
lowcost[]:V-U中的点到分支U的最短距离,也就是map_[j][closest[j]];
vis[]:是否访问,即是否在U中;
本题要求的是最小生成树,即使整个图连通且无圈的边权值的最小值,所以以哪个顶点为起始点都可以,不会影响最后的结果,我们就以V1为起始点为例。首先将closest[]数组初始化为1,U为{v1},即V-U中的顶点均与U中的v1离得最近,lowcost[i]也初始化为map_[i][1];然后遍历找到V-U中lowcost[]的最小值k,把该点加入U,即vis[k]=1;之后更新V-U的lowcost[]数组,如果到vk的距离小于原来的距离,就更新lowcost[],更新closest[];直至最后V-U为空集,然后遍历将lowcost[]中的值相加即为所求。

一点想法

求最小边权值一定是最后遍历lowcost[]数组,而不是像kruskal算法选一条边算一遍,因为在选择一个顶点加入U之后,可能会更新很多条边的值,但是下一步只会选择一条边,不知道更新的哪一条边会作为最小生成树的其中一边,所以无法在循环选顶点的循环中计算。

WA的教训

一定要分清边数和顶点数,尤其是循环比较多的时候,不然可能会像我一样惨兮兮的RE好几遍。。。。

代码实现

#include
#include
#include
using namespace std;
const int maxn=105;
const int INF=1<<29;

int n,m;//顶点数,边数
int closest[maxn];//V-U中离U最近的顶点
int lowcost[maxn];//V-U中顶点到U的最小边权值
int vis[maxn];//是否在U中
int map_[maxn][maxn];
int ans;//最低成本

void init()
{
    for(int i=1; i<=n; ++i)
    {
        closest[i]=1;
        lowcost[i]=map_[i][1];
    }
    memset(vis,0,sizeof(vis));
    ans=0;
    vis[1]=1;
    lowcost[1]=0;
}

void Prim()
{
    init();
    int i,j,k,min_num;
    for(i=1; i<=n; ++i)
    {
        min_num=INF;
        k=0;
        for(j=1; j<=n; ++j)//找到V-U中离U最近的顶点
            if(!vis[j]&&lowcost[j]

你可能感兴趣的:(算法,贪心,HDU,畅通工程,Prim,图论)