5001*5001,量太大了,直接用前缀和
整一个5001*5001的二维数组来对应整个地图,数组中的元素表示当前坐标上目标的价值(无目标即为0)
先很普通的用循环记录每个目标的坐标和价值,然后再循环计算前缀和。
计算时,每个点[i][j]上记录的价值和为 [ i ][ j ]+[ i-1 ][ j ]+[ i ][ j-1 ]-[ i-1 ][ j-1 ] (容斥原理,见下图)
因为炸弹无法破坏爆炸范围边界上的目标,所以爆炸范围为R的炸弹最多一次可以炸掉R*R个目标(画个图把范围左右移动一下就明白了),我们在计算被破坏的目标的价值和时一样用到容斥原理,[ i ][ j ]-[ i-R ][ j ]-[ i ][ j-R ]+[ i-R ][ j-R ] ,然后记录最大值就可以了
#include<iostream> using namespace std; int map[5001][5001] = {0};//二维地图上目标的价值 int main() { int n; //地图上目标的个数 int R; //爆破范围正方形的边长 cin >> n >> R; int x, y, v; //目标的坐标和价值 int boardX = 0, boardY = 0; //输入目标坐标和价值,同时计算前缀和 for (int i = 0; i < n; ++i) { cin >> x >> y >> v; map[x][y] = v; //记录一下离原点最远的目标的位置,方便提前结束循环缩短运行时间 if (x > boardX)boardX = x; if (y > boardY)boardY = y; } //计算前缀和 for (int i = 0; i <= boardX; ++i) { for (int j = 0; j <= boardY; ++j) { if (i > 0)map[i][j] += map[i - 1][j]; if (j > 0)map[i][j] += map[i][j - 1]; if (i > 0 && j > 0)map[i][j] -= map[i - 1][j - 1]; } } int maxValue = 0; //一次能炸掉的总价值的最大值 for (int i = 0; i <= boardX; ++i) { for (int j = 0; j <= boardY; ++j) { int value = map[i][j]; //这次能炸掉的总价值 if (i >= R)value -= map[i - R][j]; if (j >= R)value -= map[i][j - R]; if (i >= R && j >= R)value += map[i - R][j - R]; if (value > maxValue)maxValue = value; } } cout << maxValue; }