hdu 3440 Housu Man 差分约束系统

题意:有n个屋子,超人从最矮的屋子开始,依次跳下比当前屋子高且最接近当前高度的屋子(即按照屋子高度增序来跳),但超人跳跃还有一个水平距离限制D,他每次跳的水平距离<=D。现在给你每个屋子的高度是它们的相对位置,你不能改变屋子的相对位置,但是可以水平移动屋子,使得最矮的屋子和最高的屋子的水平距离最大。如果无论怎样移动,超人都无法跳到最后那个屋子则输出-1


分析:这题是个差分约束系统

首先得明白这题是要求最大值,那么就把每个不等式都转换成x-y<=k的形式,然后连一条y->x权值为k的边。

设di为第i个点的坐标。

先把每个楼的高度从小到大排个序,设num[i]为第i矮的楼对应的下标,那么可以得到d[num[i+1]]-d[num[i]]<=D

但有这个不等式很显然是不够的,那么我们很容易可以想到d[i+1]-d[i]<=D  d[i]-d[i-1]<=0

那么建好图后从min(num[1],num[n])到max(num[1],num[n])的最短路就是答案了。

注意数组要开int64或long long


代码

const
  maxn=1000;

var
  a,b,last:array[0..maxn] of longint;
  d:array[0..maxn] of int64;
  v:array[1..maxn] of boolean;
  state:array[1..maxn*500] of longint;
  side:array[1..maxn*10] of record
    x,y,z,next:longint;
  end;
  e,n,m,s,t,l,q:longint;

procedure qsort(l,r:longint);
var
  i,j,k:longint;
begin
  if l>=r then exit;
  i:=l;
  j:=r;
  k:=a[(i+j) div 2];
  repeat
    while a[i]<k do inc(i);
    while a[j]>k do dec(j);
    if i<=j then
    begin
      a[0]:=a[i];a[i]:=a[j];a[j]:=a[0];
      b[0]:=b[i];b[i]:=b[j];b[j]:=b[0];
      inc(i);dec(j);
    end;
  until i>j;
  qsort(i,r);
  qsort(l,j);
end;

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;

function min(x,y:longint):longint;
begin
  if x<y then exit(x)
         else exit(y);
end;

function max(x,y:longint):longint;
begin
  if x>y then exit(x)
         else exit(y);
end;

procedure init;
var
  i:longint;
begin
  e:=0;
  fillchar(last,sizeof(last),0);
  readln(n,m);
  for i:=1 to n do
  begin
    read(a[i]);
    b[i]:=i;
  end;
  readln;
  qsort(1,n);
  s:=min(b[1],b[n]);
  t:=max(b[1],b[n]);
  for i:=1 to n-1 do
  begin
    add(min(b[i],b[i+1]),max(b[i],b[i+1]),m);
    add(i+1,i,-1);
    add(i,i+1,m);
  end;
end;

procedure spfa;
var
  head,tail,i,u:longint;
begin
  for i:=1 to n-1 do
    if abs(b[i]-b[i+1])>m then
    begin
      writeln('Case ',l,': ',-1);
      exit;
    end;
  fillchar(d,sizeof(d),$7f div 3);
  d[s]:=0;
  fillchar(v,sizeof(v),true);
  v[s]:=false;
  head:=0;
  tail:=1;
  state[1]:=s;
  repeat
    inc(head);
    u:=state[head];
    i:=last[u];
    while i>0 do
      with side[i] do
      begin
        if d[x]+z<d[y] then
        begin
          d[y]:=d[x]+z;
          if v[y] then
          begin
            v[y]:=false;
            inc(tail);
            state[tail]:=y;
          end;
        end;
        i:=next;
      end;
    v[u]:=true;
  until head>=tail;
  writeln('Case ',l,': ',d[t]);
end;

begin
  readln(q);
  for l:=1 to q do
  begin
    init;
    spfa;
  end;
end.


你可能感兴趣的:(hdu 3440 Housu Man 差分约束系统)