跑步解题报告

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

问题描述:
Yali校运会又开始了。

这次校运会设置了一个有趣的项目,就是在田径场设置了很多障碍,并且在障碍之间设置了跑道,要求同学们从第s个障碍,以最快的速度跑到第t个障碍,当然不一定每个障碍都要经过。

如果把每个障碍看成一个点的话,那么这个项目就可以抽象成一个n个顶点,m 条有向边的图。

当然每个人都想走最短距离,QQ想,那么走最短路有多少种方案呢?
QQ又想,大家都走最短距离的路线可能会非常拥挤,我干脆走只比最短距离只多1的路线算了,那么,比最短路多1的路线到底有多少种方案呢?
输入格式:
第一行有四个正整数n,m,s,t。

(s<>t)
接下来m行,每行3个正整数x[i],y[i],v[i],表示有一条从x[i]到y[i]的长度为v[i]的有向边(x[i]<>y[i]),注意,数据随机生成,可能会有重边。

输出格式:
一行,用空格隔开的两个数,分别表示两问的答案mod 19940405。

输入样例:
5 6 4 1
2 3 1
3 2 1
3 1 10
4 5 2
5 2 7
5 2 7
输出样例:
2 0
样例解释:
最短路长度为20,4->5->2->3->1,注意到5->2有两条,因此有两种最短路走法。

找不到长度为21的路径,因此第2问答案为0
数据范围:v[i]<=10000
题解:改进Dijkstra算法。

将状态扩展到二维,第一维仍然是顶点编号,第二维的长度为2,分别用于记录最短路和次短路。

这样的数据有两个,dis[v][2]记录距离,count[v][2]计数。

更新状态时:
1)新值小于最短路径长:更新最短路径长,计数;次短路径长,计数
2)新值等于最短路径长:更新最短路径计数
3)新值大于最短路径长,小于次短路径长:更新次短路径长,计数
4)新值等于次短路径长:更新次短路径计数
朴素实现的Dijkstra只能得到一半左右的分数,使用堆优化可以使复杂度降到O((M+N)logN),能通过所有数据。

const cao=100000000;{即兴之作,告诉大家,编得不爽就这么干}
date=19940405;{不知道这啥日子}
var i,j,k,n,m,s,t,num,x,y,z,now,u,v:longint;
e:array[0..300000]of record
b,w,next:longint;
end;
g:array[0..60000]of longint;
a,b:array[0..110000]of longint;
dist,way,pos:array[0..60000,0..1]of longint;
f:array[0..60000]of boolean;
procedure swap(i,j:longint);
var tmp:longint;
begin
pos[a[i],b[i]]:=j;pos[a[j],b[j]]:=i;
tmp:=a[i];a[i]:=a[j];a[j]:=tmp;
tmp:=b[i];b[i]:=b[j];b[j]:=tmp;
end;{交换,交换指针就行了}
procedure up(i:longint);{上调,递归版}
begin
if i=1 then exit;
if dist[a[i],b[i]]<dist[a[i div 2],b[i div 2]] then begin
swap(i,i div 2);
up(i div 2);
end;
end;
procedure down(i:longint);{下调,递归版}
var l,r,w:longint;
begin
l:=2*i;
r:=l+1;
if (l<=num)and(dist[a[l],b[l]]<dist[a[i],b[i]]) then w:=l else w:=i;
if (r<=num)and(dist[a[r],b[r]]<dist[a[w],b[w]]) then w:=r; if w<>i then
begin
swap(i,w);
down(w);
end;
end;
begin
assign(input,'run.in');reset(input);
assign(output,'run.out');rewrite(output);
readln(n,m,s,t);
for i:=1 to n do dist[i,0]:=cao;
for i:=1 to n do dist[i,1]:=cao;
dist[s,0]:=0;
way[s,0]:=1;
for i:=1 to m do
readln(x,y,z);
e[i].b:=y;
e[i].w:=z;
e[i].next:=g[x];
g[x]:=i;
end;
for i:=1 to n do
begin
a[i*2-1]:=i;
b[i*2-1]:=0;
pos[i,0]:=2*i-1;
a[i*2]:=i;
b[i*2]:=1;
pos[i,1]:=2*i;
end;
if s>1 then swap(s*2-1,1);{建堆,其他都是CAO,满足堆性质} num:=2*n;
while ((a[1]<>t)or(b[1]=0))and(dist[a[1],b[1]]<cao) do
begin
k:=g[a[1]];
while k>0 do
if dist[a[1],b[1]]+e[k].w<dist[e[k].b,0] then
begin
dist[e[k].b,1]:=dist[e[k].b,0];
up(pos[e[k].b,1]);
way[e[k].b,1]:=way[e[k].b,0];
dist[e[k].b,0]:=dist[a[1],b[1]]+e[k].w;
up(pos[e[k].b,0]);
way[e[k].b,0]:=way[a[1],b[1]];
end{操作1}
else if dist[a[1],b[1]]+e[k].w=dist[e[k].b,0] then
way[e[k].b,0]:=(way[e[k].b,0]+way[a[1],b[1]])mod date{操作2,细节}
else if dist[a[1],b[1]]+e[k].w<dist[e[k].b,1] then
begin
dist[e[k].b,1]:=dist[a[1],b[1]]+e[k].w;
up(pos[e[k].b,1]);
way[e[k].b,1]:=way[a[1],b[1]];
end{操作3}
else if dist[a[1],b[1]]+e[k].w=dist[e[k].b,1] then
way[e[k].b,1]:=(way[e[k].b,1]+way[a[1],b[1]])mod date;{操作4}
k:=e[k].next;
end;
swap(1,num);
dec(num);
down(1);{调堆}
end;
write(way[t,0],' ');
if dist[t,1]<>dist[t,0]+1 then writeln(0){别被水了} else writeln(way[t,1]);
close(input);close(output);
end.。

相关文档
最新文档