无线网络发射器选址 题解

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/er111er/article/details/79117064

无线网络发射器选址 题解


题目大意分析

 在一个129*129的矩阵中,每个点都有一个权值,给定一个d,让你选择一个点(x,y),令(x-d,y-d)到(x+d,y+d)中的权值之和最大,并求出使权值之和最大的方案数有多少。

思路

暴力做法

 暴力做法是小学生水平,只需要从(1,1)到(129,129)(为了方便储存把横纵坐标都+1)枚举这个点,然后由(x-d,y-d)到(x+d,y+d)枚举求出权值之和,然后找出最大的权值之和。之后再这样枚举一次,找出有多少个点对应覆盖的区域的权值之和为这个最大值,这就是方案数。
 分析复杂度,会发现这是一个 O(n4) 的枚举过程,显然超时。

基于暴力的优化

 考虑原来求一个子矩阵权值之和的过程,时间复杂度为 O(n2) ,这之间有很多信息的浪费,为了提高效率,引进一个概念:

二维前缀和

 一维前缀和你肯定知道,设 sum[n] 为一维数列中 ni=1ai ,那么 ri=lai 显然为 sum[r]sum[l]
 二维前缀和也类似,设 sum[n][m] 为原二维数组中:

i=1nj=1maij

先求解sum的递推式,观察下图。
这里写图片描述
可以看出 sum[i][j] sum[i1][j] , sum[i][j1] 以及 sum[i1][j1] 推来,递推式为 sum[i][j]=sum[i1][j]+sum[i][j1]sum[i1][j1]+a[i][j]
类似的,求某一个子矩阵的和如下图(画得很丑,别介意)
这里写图片描述
欲求(x1,y1)至(x2,y2)的和,就是
sum[x2][y2]sum[x2][y11]sum[x11][y2]+sum[x11][y11]

这样就能够在 O(n2) 的预处理后O(1)求出某个子矩阵的权值之和了。
代码(C++):

#include <cmath>
#include <cstdio>
#include <cstring>
#include <cstdlib>

const int N = 137;
typedef long long ll;

int d, n, x, y, xx, yy;
ll a[N][N], sum[N][N], k, mxans = 0, mxcnt; //不开long long稳爆炸

inline int read() //读入优化
{
    int x = 0, f = 0;
    char c = getchar();
    for (; c < '0' || c > '9'; c = getchar()) if (c == '-') f = 1;
    for (; c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) + c - '0';
    return f ? -x : x;
}

inline ll min(ll a, ll b) { return a < b ? a : b; } //自定义max&&min函数加速
inline ll max(ll a, ll b) { return a > b ? a : b; }

int main()
{
    d = read(), n = read();
    for (int i = 1; i <= n; i++)
        x = read(), y = read(), k = read(),
        a[x + 1][y + 1] = k; //方便起见+1
    for (int i = 1; i <= 129; i++)
        for (int j = 1; j <= 129; j++)
            sum[i][j] = sum[i - 1][j] + sum[i][j - 1] - sum[i - 1][j - 1] + a[i][j]; //预处理sum数组
    for (int i = 1; i <= 129; i++)
        for (int j = 1; j <= 129; j++)
            x = max(i - d, 1), y = max(j - d, 1), //防止越界
            xx = min(i + d, 129), yy = min(j + d, 129), //防止越界
            mxans = max(mxans, sum[xx][yy] - sum[x - 1][yy] - sum[xx][y - 1] + sum[x - 1][y - 1]); //求出最大的值
    for (int i = 1; i <= 129; i++)
        for (int j = 1; j <= 129; j++)
        {
            x = max(i - d, 1), y = max(j - d, 1); //防止越界
            xx = min(i + d, 129), yy = min(j + d, 129); //防止越界
            if (sum[xx][yy] - sum[x - 1][yy] - sum[xx][y - 1] + sum[x - 1][y - 1] == mxans) mxcnt++; //如果等于最大的值就多一种方案
        }
    printf("%lld %lld\n", mxcnt, mxans);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/er111er/article/details/79117064