关于spaf
关于spfa的一些事宜....
刚开始学的时候只会跑最短路,代码都是背下来的。以下是背的代码...
inline void spaf(int s)
{
queue<int>q;q.push(s);
memset(dis,10,sizeof(dis));
memset(vis,0,sizeof(vis));
vis[s]=1;dis[s]=0;
while(q.size())
{
int x=q.front();q.pop();
for(int i=link[x];i;i=a[i].next)
{
int y=a[i].y;
if(dis[y]>dis[x]+a[i].v)
{
dis[y]=dis[x]+a[i].v;
if(vis[y]!=1){vis[y]=1;q.push(y);}
}
}
vis[x]=0;
}
}
虽然有很多不懂得,但拿着标版还是可以做题的。
很显然,spaf用的是链式前向星(或边表)存的图。
但光背代码是不行的,终于有一道题卡住我了...
相信大佬们一看就会了,但这道题确实卡了我许多天。
我认真的看看了题解,终于懂得spaf原来还可以这样用!
这里可以讲一下spaf的原理了,spaf其实用队列优化的工具。它其实就是bfs了,可以用来图的遍历只不过是一层一层扫的。经常用到的的就是图的单源最短路,其实就是给定一个点s,求这个点都其余所有点的最短路。证明:从队尾取出来一个"松弛"过得点,然后枚举这个点能连到的所有边,看s点到边连接的另一个点能否用这个点“松弛”,如果能的话,进行松弛,且将这个刚被松弛的点放入队尾,用它来松弛其他的点,这样每次s点到各点的距离就会减少,直至减少至最短距离。或许有人会问:那如果一直循环下去呢,怎么办?不要怕,这就是spaf另一个强大得功能,判负环。一直循坏,说明最短距离一直被更新,说明就有负环出现了。
具体的原理可以看以下的图片(讲的挺详细的,我就是看这个才有启发的):
.这只是spaf最基本的功能,根据此原理,这道题就好写了。我们可以分别用minn数组来存从起点到第i点保存的最小值,即从起点出发,无论咋走,最后走到第i点保存的最小值。这样就保证了贸易是能买到的最小值。用maxx数组来存从终点到第i点保存的最大值,即即从终点出发,无论咋走,最后走到第i点保存的最大值。保证了第i点走到终点的最大值。最后for循环枚举各个点即可。(具体细节自己考虑)
中心代码:
inline void spaf1() { queue<int>q;q.push(1); memset(minn,10,sizeof(minn)); minn[1]=awp[1];vis[1]=1; while(q.size()) { int x=q.front();q.pop(); for(int i=link1[x];i;i=a1[i].next) { int y=a1[i].y; if(minn[y]>minn[x]) { minn[y]=min(minn[x],awp[y]); if(vis[y]!=1) {q.push(y);vis[y]=1;} } } vis[x]=0; } } inline void spaf2() { queue<int>q;q.push(n); memset(vis,0,sizeof(vis)); vis[n]=1;maxx[n]=awp[n]; while(q.size()) { int x=q.front();q.pop(); for(int i=link2[x];i;i=a2[i].next) { int y=a2[i].y; if(maxx[y]<maxx[x]) { maxx[y]=max(awp[y],maxx[x]); if(vis[y]==0){vis[y]=1;q.push(y);} } } vis[x]=0; } }
来个小总结吧!spaf其实有很多功能,但只用于链表。其中依据单源最短路的原理可以跑出从某一点出发到达任何点保存的最大值和最小值(点权和边权均适用)。当然,依据其bfs搜索的原理,也可以遍历图。
不知道你学会了吗?
最后,谢谢观看鄙人的处女作!
上一篇: 处暑前后吃什么水果?处暑的习俗