bzoj 1066 最大流

61 篇文章 0 订阅
10 篇文章 0 订阅

题意:r行c列的网络中有一些高低不同的石柱,每行每列相邻石柱距离为1,一些石柱上有蜥蜴,每个蜥蜴可以跳到平面距离不超过d的任意石柱上。每次蜥蜴跳跃时离开的石柱高度减一,到达的石柱高度不变。当石柱高度为0时其他蜥蜴不能落脚。任意时刻同一个石柱上不能有超过一只的蜥蜴。让尽量多的蜥蜴逃到边界外,输出无法逃离的蜥蜴。即输出无法蜥蜴的最小值。

最大流

建图:源点连每个有蜥蜴的柱子,流量为1每个能跳到边界外的柱子(初始高度大于0的)连汇点,流量为正无穷;由于每个柱子有能走蜥蜴的限制,把每个柱子(初始高度大于0的)拆成出入两个点,每个柱子的出入两个点之间流量为石柱高度(能走蜥蜴的总数),每个出点连能到达的柱子的入点,流量为正无穷

var
        n,m,d,l,ss,st   :longint;
        s               :string;
        ans,sum,x       :longint;
        i,j,ii,jj       :longint;
        last            :array[0..1010] of longint;
        dis             :array[0..1010] of longint;
        que             :array[0..1010] of longint;
        pre,other,len   :array[0..170010] of longint;
        num             :array[0..25,0..25] of longint;
        map,jump        :array[0..25,0..25] of char;
function min(a,b:longint):longint;
begin
   if a<b then exit(a) else exit(b);
end;

procedure connect(x,y,z:longint);
begin
   inc(l);
   pre[l]:=last[x];
   last[x]:=l;
   other[l]:=y;
   len[l]:=z;
end;

function bfs:boolean;
var
        p,q,cur,h,tl:longint;
begin
   fillchar(dis,sizeof(dis),0);
   h:=0;tl:=1;
   que[1]:=ss;dis[ss]:=1;
   while (h<>tl) do
   begin
      h:=h mod 805+1;
      cur:=que[h];
      q:=last[cur];
      while (q<>0) do
      begin
         p:=other[q];
         if (len[q]>0) and (dis[p]=0) then
         begin
            tl:=tl mod 805+1;
            que[tl]:=p;
            dis[p]:=dis[cur]+1;
            if p=st then exit(true);
         end;
         q:=pre[q];
      end;
   end;
   exit(false);
end;

function dinic(x,flow:longint):longint;
var
        p,q:longint;
        rest,tt:longint;
begin
   if (x=st) then exit(flow);
   rest:=flow;
   q:=last[x];
   while (q<>0) do
   begin
      p:=other[q];
      if (dis[x]+1=dis[p]) and (len[q]>0) and (rest>0) then
      begin
         tt:=dinic(p,min(rest,len[q]));
         dec(rest,tt);
         dec(len[q],tt);
         inc(len[q xor 1],tt);
      end;
      q:=pre[q];
   end;
   exit(flow-rest);
end;


begin
   readln(n,m,d);l:=1;
   for i:=1 to n do
   begin
      readln(s);
      for j:=1 to m do map[i,j]:=s[j];
   end;
   for i:=1 to n do
   begin
      readln(s);
      for j:=1 to m do jump[i,j]:=s[j];
   end;
   //
   ss:=n*m*2+1;st:=ss+1;
   for i:=1 to n do
     for j:=1 to m do num[i,j]:=m*(i-1)+j;
   //
   sum:=0;
   for i:=1 to n do
     for j:=1 to m do
       if (jump[i,j]='L') then
       begin
          connect(ss,num[i,j],1);
          connect(num[i,j],ss,0);
          inc(sum);
       end;
   //
   for i:=1 to n do
     for j:=1 to m do
       if (map[i,j]<>'0') then
       begin
          for ii:=1 to n do
            for jj:=1 to m do
              if ((i-ii)*(i-ii)+(j-jj)*(j-jj)<=d*d) and ((i<>ii) or (j<>jj)) then
              begin
                 connect(num[i,j]+n*m,num[ii,jj],maxlongint div 10);
                 connect(num[ii,jj],num[i,j]+n*m,0);
              end;
       end;
   //
   for i:=1 to d do
     for j:=1 to m do
       if (map[i,j]<>'0') then
       begin
          connect(num[i,j]+n*m,st,maxlongint div 10);
          connect(st,num[i,j]+n*m,0);
       end;
   for i:=1 to n do
     for j:=1 to d do
       if (map[i,j]<>'0') then
       begin
          connect(num[i,j]+n*m,st,maxlongint div 10);
          connect(st,num[i,j]+n*m,0);
       end;
   for i:=n-d+1 to n do
     for j:=1 to m do
       if (map[i,j]<>'0') then
       begin
          connect(num[i,j]+n*m,st,maxlongint div 10);
          connect(st,num[i,j]+n*m,0);
       end;
   for i:=1 to n do
     for j:=m-d+1 to m do
       if (map[i,j]<>'0') then
       begin
          connect(num[i,j]+n*m,st,maxlongint div 10);
          connect(st,num[i,j]+n*m,0);
       end;
   //
   for i:=1 to n do
     for j:=1 to m do
       if (map[i,j]<>'0') then
       begin
          val(map[i,j],x);
          connect(num[i,j],num[i,j]+n*m,x);
          connect(num[i,j]+n*m,num[i,j],0);
       end;
   //
   ans:=0;
   while bfs do inc(ans,dinic(ss,maxlongint div 10));
   writeln(sum-ans);
end.
——by Eirlys


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值