3.【GDKOI2004】城市统计(city)

题目描述

中山市的地图是一个nn的矩阵,其中标号为1的表示商业区,标号为0的表示居民区。为了考察市内居民区与商业区的距离,并对此作出评估,市长希望你能够编写一个程序完成这一任务。 居民区i到商业区的距离指的是到距离它最近的商业区j的距离(|Xi-Xj|+|Yi-Yj|)(你可以理解为他们的行列分别作差),而你将统计的是对于城市中的每一个区域k,以它为中心的(2r+1)(2r+1)的矩阵区域内所有居民区到商业区的距离总和。结果同样以n*n的矩阵形式输出。

输入

第一行为t,表示以下有t组数据,每组数据之间以空行隔开,以下:
第一行为n,r(1<=r<n<=150)
第二行起为一个n*n的矩阵。

输出

t组n*n的矩阵。每组用空行隔开

样例输入

1
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

正解
用一个bfs先找出各个点最近的商业区的距离,然后用二维前缀和快速输出答案
AC代码

#include<iostream>
#include<cstdio>
using namespace std;
int n,r,a,t;
long long head,tail,x[30005],y[30005],b[155][155];
int dx[5]={
   0,1,-1,0,0};
int dy[5]={
   0,0,0,1,-1};
void bfs()//bfs找距离
{
   
	head=0;
	while(head<tail)
	{
   
		head++;
		for(int i=1;i<=4;i++)
		{
   
			int xx=x[head]+dx[i],yy=y[head]+dy[i];
			if(xx>=1&&xx<=n&&yy>=1&&yy<=n) 
			 if(b[xx][yy]>b[x[head]][y[head]]+1||b[xx][yy]==2147483647)
			 {
   
			 	b[xx][yy]=b[x[head]][y[head]]+1;
			 	tail++;
				x[tail]=xx;
				y[tail]=yy;
			 }
		}
	}
}
int main()
{
   
	freopen("city.in","r",stdin);
	freopen("city.out","w",stdout);
	cin>>t;
	while(t--)
	{
   
		tail=0;
		cin>>n>>r;
		for(int i=1;i<=n;i++)
	 	 for(int j=1;j<=n;j++)
	 	 {
   
			b[i][j]=2147483647;
			cin>>a;
	 		if(a==1){
   tail++;x[tail]=i;y[tail]=j;b[i][j]=0;}//将商业区成为起始点
	 	 } 
		bfs();
		for(int i=1;i<=n;i++)//二维前缀和
	 	 for(int j=1;j<=n;j++)
	  	  b[i][j]=b[i][j]+b[i-1][j]+b[i][j-1]-b[i-1][j-1];
	    for(int i=1;i<=n;i++)
	 	 for(int j=1;j<=n;j++)
	     {
   
	 		int x1=i-r-1,y1=j-r-1,x2=i+r,y2=j+r;
	 		x1=max(0,x1);//避免越界
			y1=max(0,y1);
	 		x2=min(n,x2);
	 		y2=min(n,y2);
	 		cout<<b[x2][y2]-b[x1][y2]-b[x2][y1]+b[x1][y1]<<' ';//通过二维前缀和输出
	 		if(j==n)cout<<endl;
	 	 }
	 	cout<<endl;  
	}
	return 0;
}

下面附本次比赛的其它题目

2020.03.18模拟赛18(第一题)
2020.03.18模拟赛18(第二题)
2020.03.18模拟赛18(第三题)
2020.03.18模拟赛18(第四题)
2020.03.18模拟赛18(总结)

谢谢