题意:有n个点和m条道路。有一些点必须经过了某些点后才能到达,问从起点到达终点的最短时间。
分析:带限制的最短路。
设d1[x]为可以进入点x的时间,d2[x]为到达点x的时间,s[x]为点x被多少个点保护。
一开始以为d1和d2是有关联的,也就是要通过d1来推出某些d2,然后想破脑袋都想不出(其实也没那么夸张啦)。后来看了题解才发现这两个可以分开求,然后进入点x的实际时间为max(d1[x],d2[x])。
然后跑dijkstra,每次找到一个d2最小且s[x]=0的点,然后更新与这个点相连的点和被这个点保护的城市dec(s).
代码:
const maxn=3007; maxm=70007; var n,m,e:longint; last,s,last1:array[1..maxn] of longint; d1,d2:array[1..maxn] of int64; side:array[1..maxm*15] of record x,y,z,next:longint; end; v:array[1..maxn] of boolean; procedure add(x,y,z:longint); begin inc(e); side[e].x:=x; side[e].y:=y; side[e].z:=z; side[e].next:=last[x]; last[x]:=e; end; procedure add1(x,y:longint); begin inc(e); side[e].x:=x; side[e].y:=y; side[e].next:=last1[x]; last1[x]:=e; end; procedure init; var x,y,z,i,j:longint; begin readln(n,m); for i:=1 to m do begin readln(x,y,z); add(x,y,z); end; for i:=1 to n do begin read(s[i]); for j:=1 to s[i] do begin read(y); add1(y,i); end; if s[i]>0 then d1[i]:=1 shl 62; end; end; function max(x,y:int64):int64; begin if x>y then exit(x) else exit(y); end; procedure dij; var u,i:longint; min,w:int64; begin for i:=2 to n do d2[i]:=1 shl 62; fillchar(v,sizeof(v),true); repeat min:=1 shl 62; u:=0; for i:=1 to n do if (v[i])and(d2[i]<min)and(s[i]=0) then begin min:=d2[i]; u:=i; end; if u>0 then begin w:=max(d1[u],d2[u]); v[u]:=false; i:=last[u]; while i>0 do with side[i] do begin if (w+z<d2[y])and(v[y]) then d2[y]:=w+z; i:=next; end; i:=last1[u]; while i>0 do with side[i] do begin dec(s[y]); if s[y]=0 then d1[y]:=w; i:=next; end; end; until u=0; writeln(max(d1[n],d2[n])); end; begin init; dij; end.