洛谷 P1514 引水入城

题目概述

   给定一个n*m的矩阵,每个格子代表高度,水只能向低处流。从最上面一排倒水,问最下面一排的每个格子是否都有水流过。若是,输出最少需在几个格子上倒水,若否,则输出最下面一排有几个格子接不到水。

解题思路

    可以证明,如果底排每个格子都有水,那么从顶部每个格子倒下的水,在底部形成的一定是一个连续的区间。

    先用广搜找出从每个格子倒下水后在底部形成区间的左右端点(需要对能否全部有水进行特殊判断),这样问题就转变成最小线段覆盖问题了,用贪心即可。

    注意:当n=1时,需要特殊判断。

              当且仅当某一顶部格子高度不低于其两边的格子时,才需要进行搜索,其他点都是多余的。

    时间复杂度:O(n*m^2)

    空间复杂度:O(n*m)

源程序

var
 a:array[0..505,0..505]of longint;
 b:array[0..505,1..2]of longint;
 c:array[0..270000,1..2]of longint;
 d:array[0..505]of boolean;
 f:array[0..505,1..2]of longint;
 g:array[0..505,0..505]of longint;
 n,m,i,j,top,tail,lb:longint;
procedure linex;
 var
  i,j,jl,now,u,t:longint;
 begin
  jl:=0;
  now:=0;
  u:=0;
  for i:=1 to m do
   if b[i,1]<=b[i,2] then begin
                           inc(jl);
                           f[jl,1]:=b[i,1];
                           f[jl,2]:=b[i,2];
                          end;
  for i:=1 to jl-1 do
   for j:=i+1 to jl do
    if f[i,1]>f[j,1] then begin
                           f[0]:=f[i];
                           f[i]:=f[j];
                           f[j]:=f[0];
                          end;
  while now<=m do
   begin
    inc(now);
    if now>m then break;
    j:=0;
    for i:=1 to jl do
     begin
      if f[i,1]>now then break;
      if f[i,2]>j then j:=f[i,2];
     end;
    inc(u);
    now:=j;
   end;
  writeln(1);
  writeln(u);
 end;
procedure search(p:longint);
 var
  maxl,maxr:longint;
 begin
  maxl:=9999;
  maxr:=-2;
  top:=0;
  tail:=1;
  c[1,1]:=1;
  c[1,2]:=p;
  while top<=tail do
   begin
    inc(top);
    if top>tail then break;
    g[c[top,1],c[top,2]]:=i;
    if (c[top,1]-1>0)and(a[c[top,1]-1,c[top,2]]<a[c[top,1],c[top,2]])and(g[c[top,1]-1,c[top,2]]<>i) then
     begin
      inc(tail);
      c[tail,1]:=c[top,1]-1;
      c[tail,2]:=c[top,2];
      if c[tail,1]=n then begin
                           if d[c[tail,2]]=false then begin
                                                       d[c[tail,2]]:=true;
                                                       dec(lb);
                                                      end;
                           if c[tail,2]>maxr then maxr:=c[tail,2];
                           if c[tail,2]<maxl then maxl:=c[tail,2];
                          end;
     end;
    if (c[top,1]+1<=n)and(a[c[top,1]+1,c[top,2]]<a[c[top,1],c[top,2]])and(g[c[top,1]+1,c[top,2]]<>i) then
     begin
      inc(tail);
      c[tail,1]:=c[top,1]+1;
      c[tail,2]:=c[top,2];
      if c[tail,1]=n then begin
                           if d[c[tail,2]]=false then begin
                                                       d[c[tail,2]]:=true;
                                                       dec(lb);
                                                      end;
                           if c[tail,2]>maxr then maxr:=c[tail,2];
                           if c[tail,2]<maxl then maxl:=c[tail,2];
                          end;
     end;
    if (c[top,2]-1>0)and(a[c[top,1],c[top,2]-1]<a[c[top,1],c[top,2]])and(g[c[top,1],c[top,2]-1]<>i) then
     begin
      inc(tail);
      c[tail,1]:=c[top,1];
      c[tail,2]:=c[top,2]-1;
      if c[tail,1]=n then begin
                           if d[c[tail,2]]=false then begin
                                                       d[c[tail,2]]:=true;
                                                       dec(lb);
                                                      end;
                           if c[tail,2]>maxr then maxr:=c[tail,2];
                           if c[tail,2]<maxl then maxl:=c[tail,2];
                          end;
     end;
    if (c[top,2]+1<=m)and(a[c[top,1],c[top,2]+1]<a[c[top,1],c[top,2]])and(g[c[top,1],c[top,2]+1]<>i) then
     begin
      inc(tail);
      c[tail,1]:=c[top,1];
      c[tail,2]:=c[top,2]+1;
      if c[tail,1]=n then begin
                           if d[c[tail,2]]=false then begin
                                                       d[c[tail,2]]:=true;
                                                       dec(lb);
                                                      end;
                           if c[tail,2]>maxr then maxr:=c[tail,2];
                           if c[tail,2]<maxl then maxl:=c[tail,2];
                          end;
     end;
   end;
  if n=1 then begin
               if d[p]=false then begin
                                           d[p]:=true;
                                           dec(lb);
                                          end;
               if p>maxr then maxr:=p;
               if p<maxl then maxl:=p;
              end;
  b[i,1]:=maxl;
  b[i,2]:=maxr;
 end;
begin
 readln(n,m);
 lb:=m;
 for i:=1 to n do
  begin
   for j:=1 to m do
    read(a[i,j]);
   readln;
  end;
 a[1,0]:=0;
 a[1,m+1]:=0;
 for i:=1 to m do
  if (a[1,i]>=a[1,i-1])and(a[1,i]>=a[1,i+1]) then search(i);
 if lb>0 then begin
               writeln(0);
               writeln(lb);
              end
         else linex;
end.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值