XYLX 10.26 虫洞/Codevs P1391 伊吹萃香
题目描述 N个虫洞,M条单向跃迁路径。
从一个虫洞沿跃迁路径到另一个虫洞需要消耗一定量的燃料和1单位时间。
虫洞有白洞和黑洞之分。
设一条跃迁路径两端的虫洞质量差为delta。
从白洞跃迁到黑洞,消耗的燃料值减少delta。
若该条路径消耗的燃料值变为负数的话,取为0。
从黑洞跃迁到白洞,消耗的燃料值增加delta。
路径两端均为黑洞或白洞,消耗的燃料值不变化。
作为压轴题,自然不会是如此简单的最短路问题,所以每过1单位时间黑洞变为白洞,白洞变为黑洞。
在飞行过程中,可以选择在一个虫洞停留1个单位时间,如果当前为白洞,则不消耗燃料,否则消耗s[i]的燃料。
现在请你求出从虫洞1到N最少的燃料消耗,保证一定存在1到N的路线。
输入输出
输入格式
第1行:2个正整数N,M
第2行:N个整数,第i个为0表示虫洞i开始时为白洞,1表示黑洞。
第3行:N个整数,第i个数表示虫洞i的质量w[i]。
第4行:N个整数,第i个数表示在虫洞i停留消耗的燃料s[i]。
第5..M+4行:每行3个整数,u,v,k
表示在没有影响的情况下,从虫洞u到虫洞v需要消耗燃料k。
输出格式 一个整数,表示最少的燃料消耗
样例 Sample
输入样例 4 5
1 0 1 0
10 10 100 10
5 20 15 10
1 2 30
2 3 40
1 3 20
1 4 200
3 4 200
输出样例 130
数据范围
对于30%的数据: 1<=N<=100,1<=M<=500
对于60%的数据: 1<=N<=1000,1<=M<=5000
对于100%的数据: 1<=N<=5000,1<=M<=30000, 1<=u,v<=N, 1<=k,w[i],s[i]<=200
其中20%的数据为1<=N<=3000的链
样例解释 1->3->4
分析
直接将初始状态和改变后的状态想象成两个平面,那么就可以拆点,将一个点的两种状态拆开然后全图跑最短路即可。最后在两种状态中取较小值。
代码如下
program line;
type point=^rec;
rec=record
e,v:longint;
s:point;
end;
var n,m,i,j,s,e,v:longint;
vertex:array[1..10000] of point;
mess,stay:array[1..5000] of longint;
state:array[1..5000] of integer;
queue:array[1..100000] of longint;
visited:array[1..10000] of boolean;
dist:array[1..10000] of longint;
head,rear:longint;
procedure insert(s,e,v:longint);
var p:point;
begin
new(p);
p^.e:=e;
if v<0 then v:=0;
p^.v:=v;
p^.s:=vertex[s];
vertex[s]:=p;
end;
procedure spfa(st:longint);
var i,j,h:longint;
p:point;
begin
for i:=1 to 2*n do
begin
dist[i]:=maxlongint;
visited[i]:=false;
end;
head:=1;
rear:=1;
queue[head]:=st;
dist[st]:=0;
visited[st]:=true;
while head<>rear+1 do
begin
p:=vertex[queue[head]];
h:=head;
visited[queue[head]]:=false;
head:=(head mod 100000) +1;
while p<>nil do
begin
if dist[p^.e]>dist[queue[h]]+p^.v
then
begin
dist[p^.e]:=dist[queue[h]]+p^.v;
if not visited[p^.e]
then
begin
rear:=(rear mod 100000) +1;
queue[rear]:=p^.e;
visited[p^.e]:=true;
end;
end;
p:=p^.s;
end;
end;
end;
begin
readln(n,m);
for i:=1 to n do
read(state[i]);
for i:=1 to n do
read(mess[i]);
for i:=1 to n do
read(stay[i]);
for i:=1 to m do
begin
readln(s,e,v);
insert(s,n+e,v+(state[s]-state[e])*abs(mess[s]-mess[e]));
insert(n+s,e,v+((state[s] xor 1)-(state[e] xor 1))*abs(mess[s]-mess[e]));
end;
for i:=1 to n do
begin
insert(i,n+i,(state[i] and 1)*stay[i]);
insert(n+i,i,((state[i] xor 1) and 1)*stay[i]);
end;
spfa(1);
if dist[n]>dist[n+n] then write(dist[n+n])
else write(dist[n]);
end.
测试结果
测试点#suika1.in 结果:AC 内存使用量: 256kB 时间使用量: 1ms
测试点#suika10.in 结果:AC 内存使用量: 2544kB 时间使用量: 28ms
测试点#suika2.in 结果:AC 内存使用量: 256kB 时间使用量: 0ms
测试点#suika3.in 结果:AC 内存使用量: 256kB 时间使用量: 1ms
测试点#suika4.in 结果:AC 内存使用量: 624kB 时间使用量: 4ms
测试点#suika5.in 结果:AC 内存使用量: 492kB 时间使用量: 0ms
测试点#suika6.in 结果:AC 内存使用量: 492kB 时间使用量: 0ms
测试点#suika7.in 结果:AC 内存使用量: 1136kB 时间使用量: 36ms
测试点#suika8.in 结果:AC 内存使用量: 1136kB 时间使用量: 34ms
测试点#suika9.in 结果:AC 内存使用量: 2672kB 时间使用量: 35ms