题目の传送门

都成了一道模板题了OvO

==============================================================================

吐槽时间

不想看的自行点目录

今天才发现自己还没有学A*
就去看了一下A*寻路, 但是只看也不行啊, 得找题练一练啊..
然后上luogu搜A*算法结果找到了这道题?
但这不应该是道图论么= =
然后看了看题解发现原来是最短路预处理然后A*
那就写嘛, 写的有模有样的大约30min?
然后过了样例, 交上去30pts, 其余RE..
然后改数组大小再交 40pts MLE…
蛤? 然后又改一遍, 40pts RE…
什么鬼咯… 然后发现自己根本tm没调用dij()这个函数…
也就是没预处理, 直接搜的, 突然觉得40pts很不错了2333
然后调用dij()就开始恒输出0了. 结果发现刚开始要反向建边?
然后就xjb改, 因为怕MLE还删掉一些数组重复利用之类的…
后来终于又过了样例 然后交上去0pts 9WA1RE…
Emmmm又是什么锅啊…
冷静分析了一波, 发现自己dij往里加点的时候是这么加的:

hp[sz++]=(zt){d[e[i].to],0,d[e[i].to]};

这tm还能过样例??????????
然后改完就能70pts RE了.
然后改两波数组大小就终于AC了.
然而要是省选干出这种事就死透了.. 最多通过对拍搞个70吧? (没准直接M掉滚粗了Emmmm

==============================================================================

题目分析

好了吐槽时间结束, 我们来看看这道题.
都说了是k短路模板, 题意就是求1->n的前k短路的长度和不超过m, 求最大的k.
我们就进行bfs, 第k次搜到n搜到的就是最短路.
但是朴素的bfs很显然是过不了的, 我们要采用启发式搜索(A*).

感觉A*好像比数论什么的要有用... 现实生活中用到A*的场合也是非常多的, 比如游戏中角色的自动寻路啊之类的都要用到A*不是...(然后再吐槽一句在markdown里打多个A*的话会出现玄学的斜体...

A*的基本形式: f(x)=g(x)+h(x), 其中
- f(x)表示从起始状态到结束状态的估价
- g(x)表示从起始状态到当前状态已经花费的代价.
- h(x)自然就是表示从当前状态到结束状态的估价咯~

其中A*算法的核心就是一个合适的h(x)的选择.
- 如果h(x)比实际值要小, 那么能得到最优解, 但是搜索范围较大, 效率较低.
- 如果h(x)比实际值要大, 那么搜索范围较小, 速度快, 但不一定能取得最优解.
- 而如果h(x)恰好等于实际值, 那么搜索将按照最优解进行, 是我们最想看到的一种情况.
- 所以我们要尽可能让自己选的h(x)接近实际值.

很幸运的是, 在k短路这个问题中, 我们刚好能取到完美地等于实际值的h(x),
我们只需要把边反向, 从终点开始求一波单源最短路就ok了.. (而且好像这题不卡spfa…

A*的过程中总是要找到f值最小的优先进行扩展, 我们就写个堆就好了..
这里倾情推荐algorithm库里的push_heap和pop_heap函数, 不管开不开O2都快的飞起, 比手写堆都快, 不知道怎么实现的.
(而且这题据说用priority_queue会MLE的说~
我们每次搜到n就用E减去这条路的长度, 如果E<0就输出当前的k就好了.

怎么说呢 这题还不能算是特别正宗的A*, 因为也不需要记录什么openset closeset, 也不需要输出路径所以不需要记录父亲之类的, 所以就这样吧…

代码

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N=5050;
const int M=2e5+8;
struct edge{int to,next;double data;}e[M]; int v[N],tot;
inline void buildedge(const int&x,const int&y,const double&z){
e[++tot].to=y;e[tot].data=z;e[tot].next=v[x];v[x]=tot;
}
struct zt{double f,g;int x;}hp[M<<3]; int sz;
inline bool operator<(const zt&a,const zt&b){return a.f>b.f;}
double d[N],Z[M],K; int n,m,X[M],Y[M];
void dij(){
for(int i=1;i<n;++i) d[i]=1e12;
d[n]=0; hp[sz++]=(zt){0,0,n};
while(sz){
::pop_heap(hp, hp+sz); zt x=hp[--sz];
if(d[x.x]<x.f) continue;
for(int i=v[x.x];i;i=e[i].next)
if(d[x.x]+e[i].data<d[e[i].to]){
d[e[i].to]=d[x.x]+e[i].data;
hp[sz++]=(zt){d[e[i].to],0,e[i].to};
::push_heap(hp, hp+sz);
}
}
}
int Astar(int s=0){
hp[sz++]=(zt){d[1],0,1};
while(sz){
::pop_heap(hp, hp+sz); zt x=hp[--sz];
if(x.f>K) break;
for(int i=v[x.x];i;i=e[i].next){
hp[sz++]=(zt){x.g+e[i].data+d[e[i].to],x.g+e[i].data,e[i].to};
::push_heap(hp, hp+sz);
}
if(x.x==n){
K-=x.f; if(K<0) break; ++s;
}
}
return s;
}
int main(){
scanf("%d%d%lf",&n,&m,&K);
for(int i=1;i<=m;++i){
scanf("%d%d%lf",&X[i],&Y[i],&Z[i]);
::buildedge(Y[i], X[i], Z[i]);
} dij();
::memset(e, 0, sizeof e);
::memset(v, 0, sizeof v); tot=0;
for(int i=1;i<=m;++i)
::buildedge(X[i], Y[i], Z[i]);
printf("%d",Astar());
}

以后数组算着空间够的话数组一定能开大就开大….
当然还是一定要避免MLE… 毕竟数组开小了还能得个部分分, MLE就直接爆零滚粗了(ノ`Д)ノ

【模板篇】k短路 SDOI2010 魔法猪学院的更多相关文章

  1. 洛谷 K短路(魔法猪学院)

    A*+迪杰特斯拉... 第十一个点卡爆 不管了 #include<iostream> #include<algorithm> #include<cstring> # ...

  2. Bzoj 1975: [Sdoi2010]魔法猪学院 dijkstra,堆,A*,K短路

    1975: [Sdoi2010]魔法猪学院 Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 1357  Solved: 446[Submit][Statu ...

  3. K短路 (A*算法) [Usaco2008 Mar]牛跑步&[Sdoi2010]魔法猪学院

    A*属于搜索的一种,启发式搜索,即:每次搜索时加一个估价函数 这个算法可以用来解决K短路问题,常用的估价函数是:已经走过的距离+期望上最短的距离 通常和Dijkstra一起解决K短路 BZOJ1598 ...

  4. [BZOJ1975][SDOI2010]魔法猪学院(k短路,A*)

    1975: [Sdoi2010]魔法猪学院 Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 2748  Solved: 883[Submit][Statu ...

  5. bzoj1975: [Sdoi2010]魔法猪学院【k短路&A*算法】

    1975: [Sdoi2010]魔法猪学院 Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 2446  Solved: 770[Submit][Statu ...

  6. bzoj 1975: [Sdoi2010]魔法猪学院 [k短路]

    1975: [Sdoi2010]魔法猪学院 裸题... 被double坑死了 #include <iostream> #include <cstdio> #include &l ...

  7. [SDOI2010]魔法猪学院(A*,最短路)

    [SDOI2010]魔法猪学院(luogu) Description 题目描述 iPig在假期来到了传说中的魔法猪学院,开始为期两个月的魔法猪训练.经过了一周理论知识和一周基本魔法的学习之后,iPig ...

  8. BZOJ_1975_[Sdoi2010]魔法猪学院_A*

    BZOJ_1975_[Sdoi2010]魔法猪学院_A* Description iPig在假期来到了传说中的魔法猪学院,开始为期两个月的魔法猪训练.经过了一周理论知识和一周基本魔法的学习之后,iPi ...

  9. bzoj 1975 [Sdoi2010]魔法猪学院

    1975: [Sdoi2010]魔法猪学院 Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 1758  Solved: 557[Submit][Statu ...

随机推荐

  1. 要素选择变化事件 IActiveViewEvents_SelectionChanged

    void IDockableWindowDef.OnCreate(object hook) { m_application = hook as IApplication; m_hookHelper = ...

  2. Pregel Worker

  3. python——pandas基础

    参考: 实验楼:https://www.shiyanlou.com/courses/1091/learning/?id=6138 <利用python进行数据分析> pandas简介 Pan ...

  4. 数据转换--替换值(replace函数)

    替换值 replace函数 data=Series([1,-999,2,-999,-1000,3]) data Out[34]: 0 1 1 -999 2 2 3 -999 4 -1000 5 3 d ...

  5. python_django_urls模块与views模块请求访问过程

    diango接收到web请求后的在urls模块与views模块进行的过程操作: 匹配过程: urls拿到网址,在项目级urls中匹配,若在urlpatterns中存在,则跳转到应用级urls中匹配,若 ...

  6. python操作redis数据

    一.环境安装 1.redispy安装 (automatic) C:\Users\Administrator>pip install redis 2.检测是否安装成功 (automatic) C: ...

  7. Bribing FIPA

    Bribing FIPA 给出多棵有n个节点的有根树,第i个节点有一个权值\(a_i\),定义一个点能控制的点为其所有的子节点和它自己,询问选出若干个点的最少的权值之和,并且能够控制大于等于m个点,\ ...

  8. 使用vue-cli脚手架和vue-router搭建项目(一)

    之前做的项目一直比较简单,并没有引入整个路由库.今天准备练习下

  9. bzoj1010题解

    [解题思路] 设s[i]=i+∑c[j](j∈[1,n]∩N) 易得转移方程f[i]=min{f[j]+(s[i]-s[j]-L-1)2},朴素算法复杂度O(n2). 考虑斜率优化:记T[i]=s[i ...

  10. bzoj1005题解

    [解题思路] 引理:Prufer编码 定义:不断删除树中度数为1的最小序号的点,并输出与其相连的节点的序号,直至树中只有两个节点,所得输出序列即为Prufer编码. 性质:任意一棵n节点的树都可以用长 ...