【日常学习】【Dijkstra堆优化】codevs2038 香甜的黄油题解

转载请注明出处 [ametake版权所有]http://blog.csdn.net/ametake

先放上题目,出自USACO

题目描述 Description

农夫John发现做出全威斯康辛州最甜的黄油的方法:糖。把糖放在一片牧场上,他知道N(1<=N<=500)只奶牛会过来舔它,这样就能做出能卖好价钱的超甜黄油。当然,他将付出额外的费用在奶牛上。

农夫John很狡猾。他知道他可以训练这些奶牛,让它们在听到铃声时去一个特定的牧场。他打算将糖放在那里然后下午发出铃声,以至他可以在晚上挤奶。

农夫John知道每只奶牛都在各自喜欢的牧场呆着(一个牧场不一定只有一头牛)。给出各头牛在的牧场和牧场间的路线,找出使所有牛到达的路程和最短的牧场(他将把糖放在那)。

输入描述 Input Description

第一行: 三个数:奶牛数N,牧场数P(2<=P<=800),牧场间道路数C(1<=C<=1450).

第二行到第N+1行: 1到N头奶牛所在的牧场号.

第N+2行到第N+C+1行: 每行有三个数:相连的牧场A、B,两牧场间距(1<=D<=255),当然,连接是双向的.

输出描述 Output Description

一行 输出奶牛必须行走的最小的距离和.

样例输入 Sample Input

3 4 5
2
3
4
1 2 1
1 3 5
2 3 7
2 4 33 4 5
样例图形
         P2
P1 @[email protected] C1
    \    |     \   |       5  7  3
       \ |           \|    \ C3
      C2 @[email protected]
         P3    P4

样例输出 Sample Output

8
{说明: 放在4号牧场最优. }

这道题目得耗了我二十多个小时 从最早的SPFA裸,到SLF和LLL优化,再到双结构体的可怜堆优化Dijkstra= =说起来都是泪啊TUT

根据朱全民在NOI导刊上的文章来看,此题最好的方法应该是SPFA

但是显然codevs加强了数据 边数剧增 导致SPFA退化到比裸的Dijkstra还慢  因为SPFA时间复杂度为O(km),m是边数,k期望为2,边数很大(比如这道题目n*(n-1),n是点数)的情况下,比dij的O(n2)显然要慢。

正如我们之前总结过的,遇到稠密图,SPFA很是苦手。

加了两个优化,原理是把可以松弛的边放在队列前面,优先队列实现。但还是超时。如下

可以看出,随着数据规模增大,时间剧增,因为边数二次函数增长

而如果用优化的Dij,效果就要好得多。堆优化的原理是运用一个最小堆(c++可以通过STL的priority_queue实现),使“查找dist最小边贪心”的复杂度降低到logn,而如果运用邻接表存储,直接查找能更新的点,更新dist的复杂度最大是n。因此堆优化后复杂度为O(nlogn),显然在稠密图中会大大降低时间复杂度。而相对于SPFA空间复杂度并没有增多很多(尤其是SPFA加了优化存储规模基本是一样的,也是写结构体+优先队列重载)。

我们来看一下dijkstra优化时间:

显而易见,小数据差别并不大,dijkstra还要慢一些,而一旦数据规模爆表,dij优势不言而喻。大数据要快10倍。

接下来放上这几次尝试的代码吧

这是最原始的SPFA 裸的可以当模板

SPFA还可以用SLF和LLL优化 两个优化本质是一样的,可以用结构体+重载小于号+优先队列实现 参见“玛丽卡”

接下来是原始版的dijkstra堆优化 和最终版区别是 元素一次性全部入队 每次最小元素出队并调整其他元素位置 这个程序WA了 但本身算法应该没有问题 我不想调试了所以先放到这里

请注意:这是错误的程序

接下来是最终版 像bfs那样 每次扩展出新的节点入队

另外,方便pascal同学们,最后附上朱全民老师pascal代码对这个题目的讲解。但是请注意,朱全民老师讲解用的是USACO原始数据,是稀疏图,最优解SPFA

——一叶扁舟轻帆卷,暂泊楚江南岸。

时间: 2024-10-11 05:38:27

【日常学习】【Dijkstra堆优化】codevs2038 香甜的黄油题解的相关文章

POJ 3013 Big Christmas Tree【最短路变形,DIjkstra堆优化+spfa算法】

Big Christmas Tree Time Limit: 3000MS   Memory Limit: 131072K Total Submissions: 23064   Accepted: 4987 Description Christmas is coming to KCM city. Suby the loyal civilian in KCM city is preparing a big neat Christmas tree. The simple structure of t

hdu 2544 单源最短路问题 dijkstra+堆优化模板

最短路 Time Limit: 5000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 41168    Accepted Submission(s): 17992 Problem Description 在每年的校赛里.全部进入决赛的同学都会获得一件非常美丽的t-shirt.可是每当我们的工作人员把上百件的衣服从商店运回到赛场的时候,却是非常累的.所以如今他们想要寻

Bzoj 2834: 回家的路 dijkstra,堆优化,分层图,最短路

2834: 回家的路 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 62  Solved: 38[Submit][Status][Discuss] Description Input Output Sample Input 2 1 1 2 1 1 2 2 Sample Output 5 HINT N<=20000,M<=100000 Source dijkstra+堆优化+分层图 把所有的横向和纵向分开看.跑最短路即可. 注意:N这么大,不能写

Heap+Dijkstra堆优化的Dijkstra

前面说到"原生的Dijkstra",由于Dijkstra采用的是贪心策略,在贪心寻找当前距离源结点最短的结点时需要遍历所有的结点,这必然会导致效率的下降,时间复杂度为n^n.因此当数据量较大时会消耗较长时间.为了提高Dijkstra的效率,只有对Dijkstra的贪心策略进行改进. 由于Dijkstra采用的贪心策略是每次寻找最短距离的结点并将其放入存放所有已知最短距离结点的S集合中,可以联想到堆以及优先级队列这些数据结构,这些结构都能非常高效地提供当前状态距离最短的结点.实践也可以证

Poj 1151 Invitation Cards dijkstra 堆优化

很裸的最短路,不过节点数和边数都是1e6,直接dij肯定是不行了,稀疏图用heap优化一下就好 o(╯□╰)o注意STL里面的优先队列是优先级大的(值大的)在前面的,一开始没注意WA了好几发,哎,太粗心了 #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <climits> #include <string> #inc

[转]浅谈dijkstra堆优化

众所周知的,dijkstra是图论算法中求单源最短路的一种简单求法.可能有人会说SPFA比dijkstra要实用,而且可以用于求存在负边权的情况,但是dijkstra有着他的优点——其运行速度上优于SPFA. (PS.需要堆进行优化.) 我们先看一道经典(水)题: 平面上有n个点(n<=100),每个点的坐标均在-10000~10000之间.其中的一些点之间有连线. 若有连线,则表示可从一个点到达另一个点,即两点之间有通路,通路的距离为两点之间的直线距离.现在的任务是找出从入点到出点之间的最短路

lfyzoj1096 最短路径问题 dijkstra堆优化

题目描述 平面上有n个点(n<=100),每个点的坐标均在-10000~10000之间.其中的一些点之间有连线. 若有连线,则表示可从一个点到达另一个点,即两点间有通路,通路的距离为两点间的直线距离.现在的任务是找出从一点到另一点之间的最短路径. 输入 第一行为整数n. 第2行到第n+1行(共n行) ,每行两个整数x和y,描述了一个点的坐标. 第n+2行为一个整数m,表示图中连线的个数. 此后的m 行,每行描述一条连线,由两个整数i和j组成,表示第i个点和第j个点之间有连线. 最后一行:两个整数

[Usaco2010 Feb]Chocolate Giving 最短路dijkstra+堆优化

本人水平有限,题解不到为处,请多多谅解 本蒟蒻谢谢大家观看 题目:传送门 最短路板子题:迪杰斯特拉+堆优化 注意:因为我建的是大根堆,所以要将距离取负,再存入大根堆堆中,这样队首就是最小值 直接套模板即可 code: 1 #include<bits/stdc++.h> 2 #define inf 0x3f3f3f3f 3 #pragma GCC optimize(3) 4 const int N=50005; 5 const int M=200002; 6 using namespace st

图论 Dijkstra+堆优化

dijkstra是一种单元最短路径算法,其能在较好时间复杂度内处理这一问题.但其对负权圈的处理让人不太满意--会陷入死循环 其思想和Prim算法差不多,都是贪心. 把图中的所有点划分为两个集合:包含远点S和不包含原点S的 每次从不包含原点S的集合中找出一个离原点S最近的点(这样就没有点能够比这个点更加接近原点,这也是其不能处理负权边的原因) 我们先考虑简单一点的情况:没有负权边 设u是不包含s中dist最小的那个点,另外v是不包含S中的任意点 如果v能更新u点<==>dist[v]+map[v