原题:
http://172.16.0.132/junior/#contest/show/1373/2
题目描述:
中山市的地图是一个n*n的矩阵,其中标号为1的表示商业区,标号为0的表示居民区。为了考察市内居民区与商业区的距离,并对此作出评估,市长希望你能够编写一个程序完成这一任务。
居民区i到商业区的距离指的是到距离它最近的商业区j的距离(|Xi-Xj|+|Yi-Yj|),而你将统计的是对于城市中的每一个区域k,以它为中心,所有满足max(|Xk-Xm|,|Yk-Ym|)<=r的区域m到商业区距离之和。结果同样以n*n的矩阵形式输出。
输入:
第一行为n,r(1<=r
输出:
n*n的矩阵。
样例输入:
4 1
1 0 0 0
1 1 0 0
0 1 1 0
0 1 0 0
样例输出:
1 4 9 8
2 5 10 9
2 4 7 7
2 3 4 4
分析:
这是一道很简单的题目。
根据题意,阶梯可分为两个阶段,首先对于给出的01图,计算出个点到商业区的距离,接下来在进行求和。
计算距离可以从商业区开始逐渐推算,设一个对列,将所有的商业区放到队列里,同时将他们的距离标为0,然后从队列头开始,察看每一个结点的上下左右,如果有未标明距离的,就将其激励标为当前结点距离+1,然后把它将入队列,当队列里所有结点均已察看,所有点到商业区的距离就计算好了。
然后是求和,如果按照一般的方法,枚举每一个点,然后以它为中心,将一个正方形内的所有点加起来求和,当数据很大的时候就会比较慢(例如n=100,r=100,m=20的时候),因为是矩阵上的求和,所以我们很容易就想到用部分和来解决。
我们设第一步计算距离完毕后的结果为矩阵a,设f[i][j]表示从矩阵a左上角到(i,j)一个矩阵内所有点的和,那么若要求以(i,j)为中心,半径为r的正方形内所有点的和,很简单就可以得到一下的算式:
answer[i][j]=f[i+r][j+r]-f[i-r-1][j+r]-f[i+r][j-r-1]+f[i-r-1][j-r-1]
当然,加上r或减去r是会导致超出矩阵1..n的范围的,要注意处理一下以免越界。
实现:
uses math;
const
m:array[1..4,1..2] of longint=((1,0),(0,1),(-1,0),(0,-1));
var
d:array[1..100007,1..2] of longint;
bz:array[0..150,0..150] of boolean;
map,dis,f:array[0..150,0..150] of longint;
t,ans,head,tail,xx,yy,n,r,x,y,i,j:longint;
procedure dfs;
begin
head:=0;
while head<>tail do
begin
head:=head mod 1000000+1;
x:=d[head,1]; y:=d[head,2];
for i:=1 to 4 do
begin
xx:=x+m[i,1]; yy:=y+m[i,2];
if dis[xx,yy]>dis[x,y]+1 then
begin
dis[xx,yy]:=dis[x,y]+1;
if not bz[xx,yy] then
begin
tail:=tail mod 1000000+1;
d[tail,1]:=xx; d[tail,2]:=yy;
bz[xx,yy]:=true;
end;
end;
end;
bz[x,y]:=false;
end;
for i:=1 to n do
for j:=1 to n do f[i,j]:=f[i-1,j]+f[i,j-1]-f[i-1,j-1]+dis[i,j];
end;
begin
assign(input,'city.in');reset(input);
assign(output,'city.out');rewrite(output);
readln(t);
while t>0 do
begin
fillchar(bz,sizeof(bz),false);
fillchar(f,sizeof(f),0);
tail:=0;
head:=0;
readln(n,r);
for i:=1 to n do
for j:=1 to n do dis[i,j]:=maxlongint div 2;
for i:=1 to n do
for j:=1 to n do
begin
read(map[i,j]);
if map[i,j]=1 then
begin
inc(tail);
d[tail,1]:=i; d[tail,2]:=j;
dis[i,j]:=0;
bz[i,j]:=true;
end;
end;
dfs;
for i:=1 to n do
begin
for j:=1 to n do
begin
x:=min(i+r,n); y:=min(j+r,n);
xx:=max(0,i-r-1);yy:=max(0,j-r-1);
ans:=f[x,y]-f[xx,y]-f[x,yy]+f[xx,yy];
write(ans,' ');
end;
writeln;
end;
writeln;
dec(t);
end;
close(input);close(output);
end.