SPFA优化:SLF,LLL,前向星

SLF:Small Label First 策略。


实现方法是,设队首元素为 i,队列中要加入节点 j,在 d[i]<=d[j] 时加到队首而不是队尾,否则和普通的 SPFA 一样加到队尾。


LLL:Large Label Last 策略。


实现方法是,设队列 Q 中的队首元素为i,距离标号的平均值为 ,每次出队时,若 d[i]>平均值,把 i 移到队列末尾,如此反复,直到找到一个 i 使  d[i]>=平均值,将其出队。


前向星:
通过前向星数据结构,对于 E<<N^2的图,效率大大提高。
对于usaco中的sweetbutter一题,有800*800的图,但只有1450的路径
所以用前向星会非常好:

var
n,p,c,i,j:longint;
a,b,e,f,cownum,sum:array[1..3000] of longint;//有点浪费
{
f数组的作用:f[x]标记的是第一个以x为一端的路径在前向星中的编号.
主要理解两端代码:
1.
在a,b,e已经以a排序过了
这相当于a[x]=y转变成了f[y]=x的形式
y的排序,是的在f[y]中可以进行统计.
难以用语言表达……
if f[a[i]]=0 then f[a[i]]:=i;
f[p+1]:=c+1;
for i:=c downto 1 do
if f[i]=0 then f[i]:=f[i+1];
2.
for i:=f[v] to f[v+1]-1 do
f[v]即与v相连的所有边在前向星中的编号
那么b[f[v]]和e[f[v]]就是和v相连路径的另一断点和边权
if dist[v]+e[i]<dist[b[i]] then
}
procedure qsort(l,r:longint);//快排,不解释
var
lt,rt,tem,mid:longint;
begin
lt:=l;
rt:=r;
mid:=a[(l+r) shr 1];
repeat
while a[lt]<mid do inc(lt);
while a[rt]>mid do dec(rt);
if lt<=rt then
begin
tem:=a[lt];a[lt]:=a[rt];a[rt]:=tem;
tem:=b[lt];b[lt]:=b[rt];b[rt]:=tem;
tem:=e[lt];e[lt]:=e[rt];e[rt]:=tem;
inc(lt);
dec(rt);
end;
until lt>rt;
if lt<r then qsort(lt,r);
if l<rt then qsort(l,rt);
end;
procedure spfa(s:longint);//前向星优化spfa
var
flag:array[1..800] of boolean;
dist:array[1..800] of longint;
q:array[1..800] of longint;
head,tail,i,v:longint;
begin
fillchar(dist,sizeof(dist),127);
fillchar(flag,sizeof(flag),false);
dist[s]:=0;
head:=0;
tail:=0;
tail:=tail mod 800 +1;
q[tail]:=s;
flag[s]:=true;
while (head<>tail) do
begin
head:=head mod 800+1;
v:=q[head];
flag[v]:=false;
for i:=f[v] to f[v+1]-1 do
begin
if dist[v]+e[i]<dist[b[i]] then
begin
dist[b[i]]:=dist[v]+e[i];
if not flag[b[i]] then
begin
tail:=tail mod 800 +1;
q[tail]:=b[i];
flag[b[i]]:=true;
end;
end;
end;
end;
for i:=1 to p do
inc(sum[i],dist[i]*cownum[s]);
end;
begin
assign(input,’butter.in’);reset(input);
assign(output,’butter.out’);rewrite(output);
readln(n,p,c);
for i:=1 to n do
begin
readln(j);
inc(cownum[j]);
end;
for i:=1 to c do
begin
readln(a[2*i-1],b[2*i-1],e[2*i-1]);
a[2*i]:=b[2*i-1];b[2*i]:=a[2*i-1];e[2*i]:=e[2*i-1];
end;
c:=c*2;
qsort(1,c);
for i:=1 to c do
if f[a[i]]=0 then f[a[i]]:=i;
f[p+1]:=c+1;
for i:=c downto 1 do
if f[i]=0 then f[i]:=f[i+1];
for i:=1 to p do
if cownum[i] <>0 then
spfa(i);
j:=maxlongint;
for i:=1 to p do
if sum[i]<j then j:=sum[i];
writeln(j);
close(input);
close(output);
end.



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值