题目描述
随着智能手机的日益普及,人们对无线网的需求日益增大。某城市决定对城市内的公共场所覆盖无线网。
假设该城市的布局为由严格平行的129条东西向街道和129条南北向街道所形成的网格状,并且相邻的平行街道之间的距离都是恒定值1。
东西向街道从北到南依次编号为0,1,2…128,南北向街道从西到东依次编号为0,1,2…128。
东西向街道和南北向街道相交形成路口,规定编号为x的南北向街道和编号为y的东西向街道形成的路口的坐标是(x,y)。
在某些路口存在一定数量的公共场所。
由于政府财政问题,只能安装一个大型无线网络发射器。
该无线网络发射器的传播范围是一个以该点为中心,边长为2*d的正方形。传播范围包括正方形边界。
现在政府有关部门准备安装一个传播参数为d的无线网络发射器,希望你帮助他们在城市内找出合适的安装地点,使得覆盖的公共场所最多。
输入格式
第一行包含一个整数d,表示无线网络发射器的传播距离。
第二行包含一个整数n,表示有公共场所的路口数目。
接下来n行,每行给出三个整数x,y,k,中间用一个空格隔开,分别代表路口的坐标(x,y)以及该路口公共场所的数量。
同一坐标只会给出一次。
输出格式
输出一行,包含两个整数,用一个空格隔开,分别表示能覆盖最多公共场所的安装地点方案数,以及能覆盖的最多公共场所的数量。
数据范围
1≤d,n≤20,
0≤x,y≤128,
0<k≤106
样例
输入样例:
1
2
4 4 10
6 6 20
输出样例:
1 30
算法1
(暴力枚举) $O(n^2*d^2)$
为了方便我们可以直接加上一个偏移量,然后枚举所有可以选择的点O(n^2),然后计算对应区间的和O(d^2),如果高于已有的结果,那么就清零,如果相等的话,就加一。
C++ 代码
#include<bits/stdc++.h>
using namespace std;
const int N=200;
int a[N][N];
int main()
{
int d,n;
cin>>d>>n;
for(int i=1;i<=n;i++)
{
int x,y,z;
cin>>x>>y>>z;
a[x+21][y+21]=z;
}
int res=1,cnt=0;
for(int i=0;i<=128;i++)
for(int j=0;j<=128;j++)
{
int sum=0;
for(int k=i+21-d;k<=i+21+d;k++)
for(int l=j+21-d;l<=j+21+d;l++)
{
sum+=a[k][l];
}
//cout<<sum<<endl;
if(sum>res)
{
res=sum;
cnt=0;
}
if(sum==res) cnt++;
}
cout<<cnt<<" "<<res<<endl;
return 0;
}
算法2
(前缀和) $O(n^2)$
我们可以在O(n^2)的时间内预先处理出来前缀和,后面在计算某个区间就只需要O(1)的时间了,因为这里是统计的前缀和,偏移量加上最后的d是会超过我们整个街道范围的2d的,所以这里我们前缀和就计算到了0到180
C++ 代码
#include<bits/stdc++.h>
using namespace std;
const int N=200;
int a[N][N],sum[N][N];
int main()
{
int d,n;
cin>>d>>n;
for(int i=1;i<=n;i++)
{
int x,y,z;
cin>>x>>y>>z;
a[x+21][y+21]=z;
}
for(int i=21;i<=180;i++)
for(int j=21;j<=180;j++)
{
sum[i][j]=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+a[i][j];
}
int res=1,cnt=0;
for(int i=0;i<=128;i++)
for(int j=0;j<=128;j++)
{
int x=i+21-d,y=j+21-d;
int x1=i+21+d,y1=j+21+d;
int s=sum[x1][y1]-sum[x1][y-1]-sum[x-1][y1]+sum[x-1][y-1];
if(s>res)
{
res=s;
cnt=0;
}
if(s==res)
{
cnt++;
}
}
cout<<cnt<<" "<<res<<endl;
return 0;
}