题意:从1出发再回到1,每条边能且只能经过一次(对于一条边 u->v 和 v->u 的时间可能是不同的但算作同一条边),求最少的时间
显然,如果我们不要求回来的话,随便跑跑最短路即可,因为我们是绝对不会经过重边的,即绝对不会走过去再走回来,这样的话我完全可以不走它。所以当你确定了第一步,即从1出发到哪个和1直接相连的点x,删去走过去的边,跑x到1的最短路即可
但是同样显然的是,枚举+最短路 你会T的很惨。。。
orz hzwer:http://hzwer.com/5227.html
以下是蒟蒻口胡(只是为了自己捯一下),正确、理性、简洁的分析请见上面hzwer的传送门
我们会发现,当我们计算与1直接相连的点x到1的满足限制的最短路的时候,会有大量重复的计算,因为无论是哪个点作为第一步,只要它能走到一点y,那么一定会顺着y到1在不经过重边的最短路走回来,那么这段路就可能被多个点重复计算,即同一条满足条件的路径可能会被多次计算、很多点也会被重复经过
考虑建一个新图,使其跑最短路的时候,去掉重复的计算。
我们设置一个虚拟终点T,最终ans=dis'[T];
我们用(x,y,z)表示原图x->y 边权为z 的边;
我们先计算出1->每个点的最短路dis[i]
令fir[i]表示从1到i的最短路上经过的第一个点,即从1到i的最短路是第一步到fir[i]走来的;
(1) 当x=1时
①如果 fir[y]=y ,则说明y就是我们选择的第一步,即dis[y]=z;那么以后一定会有点是通过这条边走过去的(至少是它自己),所以这条边完全没有建的必要
②如果 fir[y]<>y ,则说明(1,y,z)不存在我们原本的最短路上,在新图上连(1,y,z)
(2)当y=1时
①如果fir[x]=x , 则说明x的最短路是由1->x走出的,路径是1->x->1,是不能通过dis[x]+z走回1(经过2次了)的,但如果其他点走到x是可以通过x返回的,所以连(x,T,z)
②如果fir[x]<>x,则说明x的最短路是由其他点转移来的,即存在路径 1->fir[x]->...->x->1 ,所以直接连(1,T,dis[x]+z)
(3)当 x<>1 && y<>1 时
①如果fir[x]=fir[y], 则说明存在路径 1->fir[x]->..->x->y->..->1,保留(x,y,z)
②如果fir[x]<>fir[y],,则说明存在路径1->fir[x]->..->x->...->1,1->fir[y]->..->y->...->1,且第一条路径是可以通过x到y在走回1的,那么直接连(1,y,dis[x]+z)
最后在新图中重跑一遍最短路即可
var
n,m,l,size,x,y,z:longint;
t :longint;
i :longint;
last,last2 :array[0..10010] of longint;
pre2,other2,len2:array[0..400010] of longint;
pre,other,len :array[0..400010] of longint;
heap,pos,fir :array[0..10010] of longint;
dis :array[0..10010] of int64;
procedure swap(var a,b:Longint);
var
c:longint;
begin
c:=a; a:=b; b:=c;
end;
procedure connect(x,y,z:longint);
begin
inc(l);
pre[l]:=last[x];
last[x]:=l;
other[l]:=y;
len[l]:=z;
end;
procedure connect2(x,y,z:longint);
begin
inc(l);
pre2[l]:=last2[x];
last2[x]:=l;
other2[l]:=y;
len2[l]:=z;
end;
procedure heap_up(i:longint);
begin
if i=1 then exit;
while i>1 do
begin
if dis[heap[i]]>1]] then
begin
swap(heap[i],heap[i>>1]);
pos[heap[i]]:=i;
pos[heap[i>>1]]:=i>>1;
i:=i>>1;
end else exit;
end;
end;
procedure heap_down(i:longint);
var
t:longint;
begin
while i<<1<=size do
begin
if dis[heap[i]]dis[heap[(i<<1)+1]] then t:=(i<<1)+1;
if i<>t then
begin
swap(heap[i],heap[t]);
pos[heap[i]]:=i;
pos[heap[t]]:=t;
i:=t;
end else exit;
end;
end;
procedure dijkstra;
var
p,q,cur,i:longint;
begin
for i:=1 to t do dis[i]:=maxlongint*100;
dis[1]:=0;
for i:=1 to t do
begin
cur:=heap[1];
heap[1]:=heap[size];
dec(size);
heap_down(1);
//
q:=last[cur];
while (q<>0) do
begin
p:=other[q];
if dis[p]>dis[cur]+len[q] then
begin
dis[p]:=dis[cur]+len[q];
if cur=1 then fir[p]:=p else fir[p]:=fir[cur];
heap_up(pos[p]);
end;
q:=pre[q];
end;
end;
end;
procedure dijkstra2;
var
p,q,cur,i:longint;
begin
for i:=1 to t do dis[i]:=maxlongint*100;
dis[1]:=0;
for i:=1 to t do
begin
cur:=heap[1];
heap[1]:=heap[size];
dec(size);
heap_down(1);
//
q:=last2[cur];
while (q<>0) do
begin
p:=other2[q];
if dis[p]>dis[cur]+len2[q] then
begin
dis[p]:=dis[cur]+len2[q];
heap_up(pos[p]);
end;
q:=pre2[q];
end;
end;
end;
procedure rebuild;
var
i,p,q:longint;
begin
inc(t); l:=0;
for i:=1 to n do
begin
q:=last[i];
while (q<>0) do
begin
p:=other[q];
if (i=1) and (fir[p]<>p) then connect2(1,p,len[q]) else
if (p=1) and (fir[i]<>i) then connect2(1,t,dis[i]+len[q]) else
if (p=1) and (fir[i]=i) then connect2(i,t,len[q]) else
if (i<>1) and (p<>1) and (fir[p]=fir[i]) then connect2(i,p,len[q]) else
if (i<>1) and (p<>1) and (fir[p]<>fir[i]) then connect2(1,p,dis[i]+len[q]);
q:=pre[q];
end;
end;
for i:=1 to t do heap[i]:=i;
for i:=1 to t do pos[i]:=i;
size:=t;
end;
begin
read(n,m); t:=n;
for i:=1 to m do
begin
read(x,y,z);
connect(x,y,z);
read(z);
connect(y,x,z);
end;
for i:=1 to n do heap[i]:=i;
for i:=1 to n do pos[i]:=i;
size:=n;
dijkstra;
rebuild;
dijkstra2;
writeln(dis[t]);
end.
——by Eirlys