【jzoj1598】【GDKOI2004】城市统计

题目描述

中山市的地图是一个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把每个点到最近商店的距离求出来
再用前缀和求出每个点所在矩阵的距离和求出


#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int way[4][2]={{-1,0},{1,0},{0,-1},{0,1}};
int n,m,x,v[500100][2],h,t,f[200][200],ans,a[200][200],xx,yy;
bool check(int x,int y){
	return (x>0&&x<=n&&y>0&&y<=n);
}
void BFS(){
	while(h++<t){
		for(int i=0;i<4;i++){
			xx=v[h][0]+way[i][0],yy=v[h][1]+way[i][1];
			if(check(xx,yy)&&!f[xx][yy]&&a[xx][yy]<1){
				f[xx][yy]=f[v[h][0]][v[h][1]]+1;
				v[++t][0]=xx,v[t][1]=yy;
			}
		}
	}
}
int main(){
	freopen("city.in","r",stdin);
	freopen("city.out","w",stdout); 
	int T;
	scanf("%d",&T);
	while(T--){
		memset(f,0,sizeof(f));
	    scanf("%d%d",&n,&m);
	    h=0,t=0;
	    for(int i=1;i<=n;i++)
	        for(int j=1;j<=n;j++){
	    	    scanf("%d",&a[i][j]);
	    	    if(a[i][j]==1)
			       v[++t][0]=i,v[t][1]=j;
		    }
	    BFS();
	    for(int i=1;i<=n;i++)
	        for(int j=1;j<=n;j++)
	            f[i][j]+=f[i][j-1]+f[i-1][j]-f[i-1][j-1];
	    for(int i=1;i<=n;i++,printf("\n")){
	        for(int j=1;j<=n;j++){
	    	    ans=f[min(i+m,n)][min(j+m,n)];
	    	    ans+=f[max(i-m-1,0)][max(j-m-1,0)]-f[max(i-m-1,0)][min(j+m,n)]-f[min(i+m,n)][max(j-m-1,0)];
	    	    printf("%d ",ans);
		    }
	    }
	    printf("\n");
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值