首页 > 代码库 > USACO2014OPEN导航竞争(silverT2)
USACO2014OPEN导航竞争(silverT2)
导航竞争{silver题2}
【问题描述】
农民约翰的汽车安装的两个导航仪在选择路线时经常出现冲突。
他居住区域的地图上有N(2 <= N <= 10,000)个结点和M(1 <= M <= 50,000)条有向边,边i连接节点A_i (1 <= A_i <= N) 和 B_i (1 <= B_i <= N)。两个结点之间可能有多条有向边。约翰的家住在结点1,他的农场在结点N。
两个导航仪使用同一份地图,但是对一同一条边,他们标注为不同驾驶时间。对于边i, i第一个导航仪标注P_i的时间,第二个导航仪标注Q_i的时间,皆为[1..100,000]的整数。
约翰开车从家里出发去他的牧场,每当他经过一条边的时候,比如从结点X到结点Y,若某个导航仪认为这不是从结点X到农场的最短路径上的一部分的时候,就会产生抱怨。若两个导航仪都不认为,则都会产生抱怨。
请帮助约翰找到一条合适的路径,使得在他的行程中,两个导航仪抱怨的次数最少。若在经过某条边时,两个导航仪均抱怨,则抱怨次数加2。
【文件输入】gpsduel.in
第一行两个整数N和M。
接下来M行,每行四个整数,分别表示A_i, B_i ,P_i, Q_i。
【文件输出】gpsduel.out
一行,一个整数,表示最少的抱怨次数。
【输入样例1】
5 7
3 4 7 1
1 3 2 20
1 4 17 18
4 5 25 3
1 2 10 1
3 5 4 14
2 4 6 5
【输出样例1】
1
【样例1说明】
如果约翰选择的路径是1 - >2 - >4 - >5,则第一导航抱怨1 - >2路(它宁愿用1 - >3路代替)。对于其余的2 - >4 - >5,这两个导航都不会抱怨。
把bao数组的初始值赋为2,表示每条边被抱怨的次数。
首先把所有的边反过来,分别用p,q数组作为权值求N点到各点的最短路。
在求最短路的过程中,记下到某一结点的最短路径中直接与该结点相连的那条路(仅有一条)。
然后dec这些边的bao值。
最后从N点开始再求一次最短路。
dist[1]就是要求的答案。
(1500ms+的时间还是太弱了,最短路的算法需要优化。
SPFA应该会强一点。)
(不过既然会写SPFA就懒得重新打一遍最短路了)
var list,dist,start,finish,u,v,q,p,bao:array[0..100000] of longint;
temp,tip,num,n,m,i:longint;
used:array[0..50000] of boolean;
st:array[0..50000] of string;
use:array[0..100000] of string;
procedure qsort(a,b:longint);
var i,j,x,temp:longint;
begin
i:=a;
j:=b;
x:=u[(i+j) div 2];
repeat
while u[i]<x do inc(i);
while u[j]>x do dec(j);
if i<=j then begin
temp:=u[i];
u[i]:=u[j];
u[j]:=temp;
temp:=v[i];
v[i]:=v[j];
v[j]:=temp;
temp:=p[i];
p[i]:=p[j];
p[j]:=temp;
temp:=q[i];
q[i]:=q[j];
q[j]:=temp;
inc(i);
dec(j);
end;
until i>j;
if i<b then qsort(i,b);
if j>a then qsort(a,j);
end;
procedure deal;
var i,now:longint;
begin
start[u[1]]:=1;
now:=u[1];
for i:=2 to m do
if u[i]<>now then
begin
finish[now]:=i-1;
now:=u[i];
start[now]:=i;
end;
finish[now]:=m;
end;
procedure dijkstra;
var i,j,min,pos,num,mm:longint;
tip:string;
begin
for i:=1 to n do dist[i]:=maxlongint;
dist[n]:=0;
fillchar(used,sizeof(used),false);
for i:=1 to n-1 do
begin
min:=maxlongint;
for j:=1 to n do
if not used[j] then
if dist[j]<min then
begin
min:=dist[j];
pos:=j;
end;
used[pos]:=true;
for j:=start[pos] to finish[pos] do
if dist[pos]+p[j]<dist[v[j]] then
begin
dist[v[j]]:=dist[pos]+p[j];
list[v[j]]:=j;
end;
end;
for i:=1 to n-1 do dec(bao[list[i]]);
end;
procedure dijkstra1;
var i,j,pos,min:longint;
begin
for i:=1 to n do dist[i]:=maxlongint;
dist[n]:=0;
fillchar(used,sizeof(used),false);
for i:=1 to n-1 do
begin
min:=maxlongint;
for j:=1 to n do
if not used[j] then
if dist[j]<min then
begin
min:=dist[j];
pos:=j;
end;
used[pos]:=true;
for j:=start[pos] to finish[pos] do
if dist[pos]+bao[j]<dist[v[j]] then
dist[v[j]]:=dist[pos]+bao[j];
end;
end;
begin
//assign(input,‘silver2.in‘);
//assign(output,‘silver2.out‘);
//reset(input);
//rewrite(output);
readln(n,m);
for i:=1 to m do
readln(u[i],v[i],p[i],q[i]);
for i:=1 to m do
begin
temp:=u[i];
u[i]:=v[i];
v[i]:=temp;
end;
qsort(1,m);
deal;
for i:=1 to m do bao[i]:=2;
dijkstra;
for i:=1 to m do p[i]:=q[i];
dijkstra;
dijkstra1;
writeln(dist[1]);
//close(input);
//close(output);
end.
(其实刚开始我把最短路径的每一条边都记下来了,
感谢YHZ的提醒……毕竟我们刚开始理解错的方式如出一辙。)
USACO2014OPEN导航竞争(silverT2)