hiho一下 第二十九周 最小生成树三·堆优化的Prim算法【14年寒假弄了好长时间没搞懂的prim优化:prim算法+堆优化 】

题目1 : 最小生成树三·堆优化的Prim算法

时间限制:10000ms

单点时限:1000ms

内存限制:256MB

描述

回到两个星期之前,在成功的使用Kruscal算法解决了问题之后,小Ho产生了一个疑问,究竟这样的算法在稀疏图上比Prim优化之处在哪里呢?

提示:没有无缘无故的优化!

输入

每个测试点(输入文件)有且仅有一组测试数据。

在一组测试数据中:

第1行为2个整数N、M,表示小Hi拥有的城市数量和小Hi筛选出路线的条数。

接下来的M行,每行描述一条路线,其中第i行为3个整数N1_i, N2_i, V_i,分别表示这条路线的两个端点和在这条路线上建造道路的费用。

对于100%的数据,满足N<=10^5, M<=10^6,于任意i满足1<=N1_i, N2_i<=N, N1_i≠N2_i, 1<=V_i<=10^3.

对于100%的数据,满足一定存在一种方案,使得任意两座城市都可以互相到达。

输出

对于每组测试数据,输出1个整数Ans,表示为了使任意两座城市都可以通过所建造的道路互相到达至少需要的建造费用。

样例输入
5 29
1 2 674
2 3 249
3 4 672
4 5 933
1 2 788
3 4 147
2 4 504
3 4 38
1 3 65
3 5 6
1 5 865
1 3 590
1 4 682
2 4 227
2 4 636
1 4 312
1 3 143
2 5 158
2 3 516
3 5 102
1 5 605
1 4 99
4 5 224
2 4 198
3 5 894
1 5 845
3 4 7
2 4 14
1 4 185
样例输出
92分析:之前弄了好长时间,看了好多材料也没搞懂怎么优化prim。今天在操作系统课上,不小心走神了。于是乎,只花了几分钟就想出来了到底要怎么优化。之前看别人的博客什么的,感觉很复杂。现在把我的想法写出来:堆优化prim算法:首先我们先想,之前在写prim的时候需要这样做,从当前的生成树开始,遍历所有可以抵达当前生成树的边,找到一条最短的边,将该边的权值加到生成树的权值总和上,加该点标记访问,并加到生成树上来。现在如果我们可以优化方法找到那条最短边的话,那复杂度不就降低了。怎么优化呢?之前的做法是用一个数组保存每个节点到生成树的距离,每次找的过程都要遍历一次这个数组。现在我们用一个优先队列(小根堆)来保存所有可以抵达生成树的边,每次只要取出该队列的最前面的且合法的边加到生成树上来就醒了。不合法的边会在这个过程中丢弃!有图有文字的描述过程如下:

代码:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <math.h>
#include <iostream>
#include <string>
#include <stack>
#include <vector>
#include <set>
#include <queue>
#include <algorithm>
#define LL long long int
#define N 100000+10 //最大节点数
#define M 1000000+10 //最大的边数
#define MOD 142857
//N<=10^5, M<=10^6

using namespace std;
int n, m;
struct node
{
    int v, w;
    bool operator<(const node &dd)const{
        return w>dd.w;
    } //权值小的优先
};
vector<node>q[N];
bool vis[N];
//堆优化的prim算法
LL ans;

void queue_prim()
{
    //以节点1为起点进行扩展安全边 生成最小树
    priority_queue<node>que;
    while(!que.empty())
        que.pop(); //初始化清空优先队列 维护一个小根堆
                  //这样每次找安全边的速度就提高了
    ans = 0;
    memset(vis, false, sizeof(vis));
    for(int i=0; i<q[1].size(); i++){
        que.push(q[1][i]); //将起点的所有连接边全部加入队列中来
    }
    vis[1]=true;
    int edge=n-1;//边数
    node cur;
    while(edge--)
    {
        cur = que.top();
        que.pop();//这个地方需要注意一下
                  //并不是每个从优先队列取出来的边都是可以加到生成树上去的

        if(vis[cur.v]==true){
            while(vis[cur.v]){
                cur=que.top(); que.pop();
            }
        }
        ans = ans+cur.w; //printf("%d--  ", cur.w );
        vis[cur.v]=true; //加入生成树的该点将被标记访问
        for(int i=0; i<q[cur.v].size(); i++){
            if(vis[ q[cur.v][i].v ]==false) //当前加入生成树的点可以扩充出的边指向的节点
                que.push(q[cur.v][i]);//如果没有被访问才会加入到队列当中来
        }
    }
}

int main()
{
    scanf("%d %d", &n, &m);
    int i, j;
    int u, v, w;
    node cur;
    for(i=0; i<=n; i++)
        q[i].clear();

    for(i=0; i<m; i++)
    {
       scanf("%d %d %d", &u, &v, &w);
       cur.v=v; cur.w=w;
       q[u].push_back(cur);
       cur.v=u;
       q[v].push_back(cur); //建立双向边
    }
    queue_prim();
    printf("%lld\n", ans );
    return 0;
}

 
时间: 2024-10-16 19:01:17

hiho一下 第二十九周 最小生成树三·堆优化的Prim算法【14年寒假弄了好长时间没搞懂的prim优化:prim算法+堆优化 】的相关文章

hiho一下 第二十六周---最小生成树一&#183;Prim算法

最小生成树一·Prim算法 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 最近,小Hi很喜欢玩的一款游戏模拟城市开放出了新Mod,在这个Mod中,玩家可以拥有不止一个城市了! 但是,问题也接踵而来--小Hi现在手上拥有N座城市,且已知这N座城市中任意两座城市之间建造道路所需要的费用,小Hi希望知道,最少花费多少就可以使得任意两座城市都可以通过所建造的道路互相到达(假设有A.B.C三座城市,只需要在AB之间和BC之间建造道路,那么AC之间也是可以通过这两条道路连通的

hihocoder hiho一下 第二十六周 最小生成树一&#183;(Prim算法)

题目1 : 最小生成树一·Prim算法 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 最近,小Hi很喜欢玩的一款游戏模拟城市开放出了新Mod,在这个Mod中,玩家可以拥有不止一个城市了! 但是,问题也接踵而来——小Hi现在手上拥有N座城市,且已知这N座城市中任意两座城市之间建造道路所需要的费用,小Hi希望知道,最少花费多少就 可以使得任意两座城市都可以通过所建造的道路互相到达(假设有A.B.C三座城市,只需要在AB之间和BC之间建造道路,那么AC之间也是可以通过这

【hiho】hiho第二十九周&#183;扫雷I

题目描述: 大致是这样的,给你长度为n的序列,每个序列上的数代表半径为2的范围内有多少个地雷,问你至多能确定多少个位置的放置,并输出一定有雷的个数及位置序列.一定没有雷的个数及位置序列 思路: 题目数据范围不是很大,O(n)吧 第一个位置确定后,按照arr[1]来说,第二个位置也就确定了 同理,对于arr[2]来说,第三个位置也就确定了..... 但是还是WA了两次,因为他问的是一定确定的! 这里就有一种情况,第一个位置放雷和不放雷都可行,那么虽然满足,但是有些位置是不确定的! 所以flag1,

hihoCoder - hiho一下 第二十六周 - A - 最小生成树一&#183;Prim算法

题目1 : 最小生成树一·Prim算法 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 最近,小Hi很喜欢玩的一款游戏模拟城市开放出了新Mod,在这个Mod中,玩家可以拥有不止一个城市了! 但是,问题也接踵而来--小Hi现在手上拥有N座城市,且已知这N座城市中任意两座城市之间建造道路所需要的费用,小Hi希望知道,最少花费多少就可以使得任意两座城市都可以通过所建造的道路互相到达(假设有A.B.C三座城市,只需要在AB之间和BC之间建造道路,那么AC之间也是可以通过这两

hiho一下 第二十五周(SPFA)

时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 万圣节的晚上,小Hi和小Ho在吃过晚饭之后,来到了一个巨大的鬼屋! 鬼屋中一共有N个地点,分别编号为1..N,这N个地点之间互相有一些道路连通,两个地点之间可能有多条道路连通,但是并不存在一条两端都是同一个地点的道路. 不过这个鬼屋虽然很大,但是其中的道路并不算多,所以小Hi还是希望能够知道从入口到出口的最短距离是多少? 提示:Super Programming Festival Algorithm. 输入 每个测试点

hihocoder 第二十九周 堆优化的Prim算法

又深刻理解了一遍prim和dijkstra算法,感觉蛮棒的~ 第一次自己用邻接表写,just soso~ 啊哈~ 一开始被优先队列,重载运算符给卡住了~ 蛋疼~ 1 #include<iostream> 2 #include<cstdio> 3 #include<cstdlib> 4 #include<cstring> 5 #include<string> 6 #include<queue> 7 #include<algorit

【WPF学习】第二十九章 元素绑定——将元素绑定到一起

原文:[WPF学习]第二十九章 元素绑定--将元素绑定到一起 数据banding的最简单情形是,源对象时WPF元素而且源属性是依赖性属性.前面章节解释过,依赖项属性具有内置的更改通知支持.因此,当在源对象中改变依赖项属性的值时,会立即更新目标对象中的绑定属性.这正是我们所需要的行为--而且不必为此构建任何额外的基础结构. 为理解如何将一个元素绑定到另一个元素,下面创建一个简单的示例.该示例窗口包含了两个控件:一个Slider控件和一个具有单行文本的TextBlock控件.如果向右拖动滑动条上的滑

NeHe OpenGL教程 第二十九课:Blt函数

转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线教程的编写,以及yarn的翻译整理表示感谢. NeHe OpenGL第二十九课:Blt函数 Blitter 函数: 类似于DirectDraw的blit函数,过时的技术,我们有实现了它.它非常的简单,就是把一块纹理贴到另一块纹理上. 这篇文章是有Andreas Lffler所写的,它写了一份原始的教

Gradle 1.12用户指南翻译——第二十九章. Checkstyle 插件

其他章节的翻译请参见: http://blog.csdn.net/column/details/gradle-translation.html 翻译项目请关注Github上的地址: https://github.com/msdx/gradledoc/tree/1.12. 直接浏览双语版的文档请访问: http://gradledoc.qiniudn.com/1.12/userguide/userguide.html. 另外,Android 手机用户可通过我写的一个程序浏览文档,带缓存功能的,目前