bzoj 1579 [Usaco2009 Feb]Revampi…

http://www.lydsy.com/JudgeOnline/problem.php?id=1579
http://poj.org/problem?id=3635
两题实在长,我就不贴了。

这两题的做法都是一样的,在dij的时候多加一维分别表示当前剩余的更新次数(poj里面是余油量)。
很多人都是开个二维数组搞的,但是今天看到一个拆点的做法相当神奇~~原文地址如下:
http://hi.baidu.com/lrc2222/blog/item/e40177f76c37b338720eecc7 .html

大意就是把n个点分成k层,k即原方法中的第二位,然后把0长度的边连在不同的层之间表示更新路径使时间为0,相同层里面的点连原时间长度的边表示不更新路径直接走。最后在每一层里面的终点值里取个最优的输出。

对于poj里面的那题所连的边都是在不同层之间的。向较上一层的自己连一条长度为一单位油价的边表示加油,向下d层的j点连一条权值为0的边表示有一条长度为d的路与j连接。
这样建完图就是裸裸的dij+heap了~~~

不过poj上的那题一早上总是超时。。。怎么卡时都不过。。。后来看标程发现一个露加的优化:
当第0层的终点有值的时候就退出。
因为用的是dij,正确性显而易见。。。
但是bzoj上的那道题就不能用这个优化了。。。有可能k次更新不许要都用完就已经走到了。。。

这里就贴一个poj上的代码吧、、

AC CODE


{$inline on}
program pku_3635;
const maxn=99999999;
var line,next,g:array[1..2100000] of longint;
      en,dist,pi,heap:array[1..101000] of longint;
      c:array[1..1000] of longint;
      lim,s,t,n,len,tot,capa:longint;
//=========================================================================
procedure ins(x,y,z:longint); inline;
begin
  inc(len); line[len]:=y; g[len]:=z;
  next[len]:=en[x]; en[x]:=len;
end;
//=========================================================================
procedure init; inline;
var i,j,m,x,y,z:longint;
begin
  readln(n,m);
  for i:=1 to n do read(c[i]);
  for i:=1 to m do
  begin
      readln(x,y,z);
      inc(x); inc(y);
      for j:=z to 100 do
      begin
          ins(j*n+x,(j-z)*n+y,0);
          ins(j*n+y,(j-z)*n+x,0);
      end;
  end;
  for i:=1 to n do
      for j:=1 to 100 do
          ins((j-1)*n+i,j*n+i,c[i]);
end;
//=========================================================================
procedure swap(x:longint); inline;
var tt:longint;
begin
  tt:=pi[heap[x]]; pi[heap[x]]:=pi[heap[x shr 1]]; pi[heap[x shr 1]]:=tt;
  tt:=heap[x]; heap[x]:=heap[x shr 1]; heap[x shr 1]:=tt;
end;
//=========================================================================
procedure update(x:longint); inline;
begin
  while x>1 do
      if dist[heap[x]]<dist[heap[x shr 1]] then
      begin
          swap(x);
          x:=x shr 1;
      end else break;
end;
//=========================================================================
procedure insert(x:longint); inline;
begin
  inc(tot); heap[tot]:=x; pi[x]:=tot;
  update(tot);
end;
//=========================================================================
procedure del; inline;
var i,g,h:longint;
begin
  pi[heap[tot]]:=0; heap[1]:=heap[tot]; dec(tot); i:=1;
  while i<tot do
  begin
      g:=i shl 1; h:=i shl 1+1;
      if (g<=tot) and (dist[heap[i]]>dist[heap[g]]) then
      begin
          if (h<=tot) and (dist[heap[g]]>dist[heap[h]]) then
          begin
              swap(h);
              i:=h;
          end else
          begin
              swap(g);
              i:=g;
          end;
      end else
      if (h<=tot) and (dist[heap[i]]>dist[heap[h]]) then
      begin
          swap(h);
          i:=h;
      end else break;
  end;
end;
//=========================================================================
procedure dij_heap; inline;
var i,j,u,v,ans:longint;
begin
  for i:=0 to capa do
      for j:=1 to n do
      begin
          dist[i*n+j]:=maxn;
          pi[i*n+j]:=0;
      end;
  heap[1]:=s; tot:=1; pi[s]:=1; dist[s]:=0;
  while tot>0 do
  begin
      u:=heap[1]; pi[u]:=0; del; i:=en[u];
      while i<>0 do
      begin v:=line[i];
          if v<=lim then
              if dist[u]+g[i]<dist[v] then
              begin
                  dist[v]:=dist[u]+g[i];
                  if pi[v]=0 then insert(v) else
                      update(pi[v]);
              end;
          i:=next[i];
      end;
      if dist[t]<maxn then break;      //就是加了这句优化就过了、、
  end; ans:=maxn;
  for i:=0 to capa do
      if dist[i*n+t]<ans then
          ans:=dist[i*n+t];
  if ans=maxn then
      writeln('impossible') else
          writeln(ans);
end;
//=========================================================================
procedure main; inline;
var query:longint;
begin
  readln(query);
  for query:=1 to query do
  begin
      readln(capa,s,t);
      inc(s); inc(t);
      lim:=capa*n+n;      //因为有油箱容量的限制,有些点是非法的、、
      dij_heap;
  end;
end;
//=========================================================================
begin
  while not(eof) do
  begin
      init;
      main;
  end;
end.
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值