bzoj 1922: [Sdoi2010]大陆争霸 带限制最短路

来源:互联网 发布:烤漆哑铃知乎 编辑:程序博客网 时间:2024/05/22 11:42

题意:有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.


0 0
原创粉丝点击