还有八九十天就NOIP了,我还是要复习一下最短路这类关键的知识点.
原来认为dijkstra堆优化和spfa会一个就行,spfa时间优,码长短.但是近几年spfa不考了.(总是被出题人D)。故意构造数据可以卡到O(k*n^2),有可能跑不过裸dij,所以今天的内容是dijkstra的堆优化,但不会dijkstra也没关系,我现在讲一下.
dijkstra是一个单源最短路.起点固定来求. 我们设起点为S.dis[i]表示由S到达i的最短路径.
那么我们可以从S点开始枚举.运用蓝白点的思维.先把S标志为蓝点表示它已经是dis[i]的最终结果了,显然dis[S]=0;
之后找到一个除了S点以外值最小的点,继续将其标志为蓝点.并把经过点的最短路径修改.手画一张图看着会更清晰些.
如果我们将原点设为1.dis[1]成为蓝点. 之后dis[2]=2,dis[3]=4,dis[4]=7;
第二轮dis[2]变为最小值,将2变为蓝点.dis[3]=3,dis[5]=4;
第三轮dis[3]最小,把3变为蓝点.dis[4]=4;
但是我们发现一个问题.第一次边权最小时就不再遍历.dijkstra及其堆优化都不能处理此类问题.(边权为负).
时间复杂度O(n^2);因为每个点都被修改n次,实际上常数可以小一点.
一道裸例题洛谷P3371,并附上AC代码.如果不够做.题号会在之后公布.(按难度排序)
#include
int head[500001];
int to[500001];
int next[500001];
int val[500001];
int idx;
bool vis[10001];
int dis[10001];
void addedge(int a,int b,int c)
{
next[++idx]=head[a];
head[a]=idx;
to[idx]=b;
val[idx]=c;
}//链式存储
int main()
{
int n,m,s,a,b,c;
scanf("%d%d%d",&n,&m,&s);
for(int i=1;i<=m;i++)
{
scanf("%d%d%d",&a,&b,&c);
addedge(a,b,c);
}
for(int i=1;i<=n;i++)
dis[i]=2147483647;//因为是最短路,所以要附上最大值.
dis[s]=0;
for(int i=1;i<=n;i++)
{
int minn=2147483647,t=-1;
for(int j=1;j<=n;j++)
{
if(!vis[j]&&dis[j]val[i]+dis[t])
dis[to[i]]=val[i]+dis[t];//每个点更新最小值
}
}
for(int i=1;i<=n;i++)
printf("%d ",dis[i]);//输出答案
}
https://neooj.com:8082/oldoj/
VIJOS-P1635 城市连接(JDOJ1594)
USACO 2009 Jan Silver 1.Best Spot(JDOJ2612)
USACO 2009 Open Silver 1.Hide and Seek(JDOJ2641)
[NOIP2001]CAR的旅行路线 T4(JDOJ1288)
USACO 2014 Feb Gold 1.Roadblock(JDOJ2406,2408,2278三倍经验)
下面讲下dijkstra堆优化.堆大家应该都知道,不知道现学一下,用STL之后会很简单明了.
我们维护一个关于边权的小根堆.在找与一个点最小边权时,用堆来维护.直接找到最小值.把那一维n缩减为logE,如果写得好一点可以减为logn
每次我们直接在堆中操作
用priority_queue可以实现这个功能.但是NOIP如果不开O2的话用pbds的堆
我写的是nlogn的,用了priority_queue
// luogu-judger-enable-o2
#include
#include
#include
#include
using namespace std;
int nex[400001];
int to[400001];
int val[400001];
int head[200001];
int f[200001];
int idx,x,y,z;
int inf=2147483647;
bool vis[200001];
struct Point
{
int number,dis;
inline bool operator < (const Point &a) const
{
return dis>a.dis;
}
};
priority_queue q;
void addedge(int a,int b,int c)
{
nex[++idx]=head[a];
head[a]=idx;
to[idx]=b;
val[idx]=c;
}
int n,m,s;
int main()
{
Point tmp;
scanf("%d%d%d",&n,&m,&s);
for(int i=1;i<=m;i++)
{
scanf("%d%d%d",&x,&y,&z);
addedge(x,y,z);
}
for(int i=1;i<=n;i++)
f[i]=inf;
tmp.number=s,tmp.dis=0;
f[tmp.number]=0;
q.push(tmp);
while(!q.empty())
{
int here=q.top().number;
q.pop();
if(vis[here])
continue;
vis[here]=1;
for(int j=head[here];j;j=nex[j])
if(f[to[j]]>val[j]+f[here]&&(!vis[to[j]]))
{
f[to[j]]=f[here]+val[j];
tmp.number=to[j];
tmp.dis=f[to[j]];
q.push(tmp);
}
}
for(int i=1;i<=n;i++)
printf("%d ",f[i]);
}
题号:洛谷P4779
JDOJ2208 短(我发过spfa的题解)
再次给个链接https://neooj.com:8082/oldoj/
USACO Sweet Butter 香甜的黄油(JDOJ1803)
USACO 2014 Dec Silver 1.Piggyback(JDOJ2911)
JDOJ1070 phoneline(dij很难做,最好用spfa)
好了,今天就到这里了.(其实是博主也没什么会的了)