激光炸弹
*一种新型的激光炸弹,可以摧毁一个边长为 R 的正方形内的所有的目标。
现在地图上有 N 个目标,用整数Xi,Yi表示目标在地图上的位置,每个目标都有一个价值Wi。
激光炸弹的投放是通过卫星定位的,但其有一个缺点,就是其爆炸范围,即那个边长为 R 的正方形的边必须和x,y轴平行。
若目标位于爆破正方形的边上,该目标不会被摧毁。
求一颗炸弹最多能炸掉地图上总价值为多少的目标。
输入格式
第一行输入正整数 N 和 R ,分别代表地图上的目标数目和正方形的边长,数据用空格隔开。
接下来N行,每行输入一组数据,每组数据包括三个整数Xi,Yi,Wi,分别代表目标的x坐标,y坐标和价值,数据用空格隔开。
输出格式
输出一个正整数,代表一颗炸弹最多能炸掉地图上目标的总价值数目。
数据范围
0<N≤10000,
0≤Xi,Yi≤5000
输入样例:
2 1
0 0 1
1 1 1
输出样例:
1*
时/空限制: 10s / 168MB
其实这是一道典型的二维前缀和的题目。
什么是前缀和呢?
我们先来看最简单的一维的前缀和,假设有一个数组:a[0]到a[n],用s[0]到s[n]表示a数组0到n的前缀和。
首先让s[0]=a[0],那么后面的前缀和s[i]就可以用s[i] = a[i] + s[i-1]
来表示。
二维前缀和其实也差不多,假设有一个大小为 n*m 的矩阵,坐标为 i , j 的元素,前缀和s[ i ][ j ]就是点( i , j )与点
( 0 , 0 )形成的矩形内的所有元素之和。
重点:我们可以通过前缀和来求出任意一个小矩形的总元素之和。
有了这个知识自然这道题就迎刃而解。
#include<bits/stdc++.h>//万能头文件
using namespace std;
int a[5001][5001],s[5001][5001];//a数组用来保存输入的数据,s数组用来求前缀和
int main()
{
int n,x,y,w,r,MAX=0,ans=0,k;//MAX用来求出需要求前缀和的边界值,避免循环多次超时
cin>>n>>r;
for(int i=0;i<n;i++)
{
scanf("%d %d %d",&x,&y,&w);
a[x][y]=w;
if(x>MAX)
MAX=x;
if(y>MAX)
MAX=y;
}
s[0][0]=a[0][0];
for(int i=1;i<=MAX;i++)
{
s[0][i]=a[0][i]+s[0][i-1];
s[i][0]=a[i][0]+s[i-1][0];
}
for(int i=1;i<=MAX;i++)
{
for(int j=1;j<MAX;j++)
{
s[i][j]=s[i-1][j]+s[i][j-1]+a[i][j]-s[i-1][j-1];//这里利用了动态规划的思想
}
}
for(int i=r-1;i<=MAX;i++)
{
for(int j=r-1;j<=MAX;j++)
{
if(i==r-1&&j==r-1)//用if else防止越界
k=s[i][j];
else if(i+1-r<=0)
k=s[i][j]-s[i][j-r];
else if(j+1-r<=0)
k=s[i][j]-s[i-r][j];
else
k=s[i][j]-s[i-r][j]-s[i][j-r]+s[i-r][j-r];
if(k>ans)
ans=k;
}
}
printf("%d\n",ans);
return 0;
}
有了这个代码所有样例基本都过了,但是并不能AC。。。。。。。。。。。。。。
提交时会发现提升你内存超限制了。。。。。。很坑
仔细想一下就会发现其实s数组是多余的,a数组用来求s数组的数据求过的数据就不需要了。
于是就有了下面这个代码
#include<bits/stdc++.h>
using namespace std;
int a[5001][5001];
int main()
{
int n,x,y,w,r,MAX=0,ans=0,k;
cin>>n>>r;
for(int i=0;i<n;i++)
{
scanf("%d %d %d",&x,&y,&w);
a[x][y]=w;
if(x>MAX)
MAX=x;
if(y>MAX)
MAX=y;
}
for(int i=1;i<=MAX;i++)
{
a[0][i]=a[0][i]+a[0][i-1];
a[i][0]=a[i][0]+a[i-1][0];
}
for(int i=1;i<=MAX;i++)
{
for(int j=1;j<MAX;j++)
{
a[i][j]=a[i-1][j]+a[i][j-1]+a[i][j]-a[i-1][j-1];
}
}
for(int i=r-1;i<=MAX;i++)
{
for(int j=r-1;j<=MAX;j++)
{
if(i==r-1&&j==r-1)
k=a[i][j];
else if(i+1-r<=0)
k=a[i][j]-a[i][j-r];
else if(j+1-r<=0)
k=a[i][j]-a[i-r][j];
else
k=a[i][j]-a[i-r][j]-a[i][j-r]+a[i-r][j-r];
if(k>ans)
ans=k;
}
}
printf("%d\n",ans);
return 0;
}
其实这个代码还可以更加精简,这里我认为没有必要了(其实是懒),有需要的可以自行修改。