题目概述
给定一个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.