弹珠游戏

GitHub跳转原题关系图返回列表

先预处理每一行和每一列的敌人数总和,再在所有空位上取行和加列和的最大值。

OJ: luogu

题目 ID: P2356

难度:普及-

标签:模拟枚举

日期: 2026-06-18 23:54

题意

给定一个 n x n 的矩阵。
正数表示该位置敌人的数量,0 表示这个位置为空,可以站人。
如果站在一个空位 (i,j),就能消灭第 i 行和第 j 列里的所有敌人。
要求输出能消灭敌人数的最大值。

思路

先看一个最直接的朴素解:

枚举每个空位,然后重新扫描它所在的整行和整列,统计这个位置能打到多少敌人。

cpp
// brute.cpp:小数据暴力解,用来帮助理解题意并辅助对拍。
#include <bits/stdc++.h>
using namespace std;

const int MAXN = 105;

int n;
int a[MAXN][MAXN];

void solve() {
    int ans = 0;

    // 枚举每一个空位,真的把该行该列的敌人全部统计一遍。
    for (int x = 1; x <= n; x++) {
        for (int y = 1; y <= n; y++) {
            if (a[x][y] != 0) {
                continue;
            }

            int cur = 0;
            for (int j = 1; j <= n; j++) {
                cur += a[x][j];
            }
            for (int i = 1; i <= n; i++) {
                cur += a[i][y];
            }

            ans = max(ans, cur);
        }
    }

    cout << ans << '\n';
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    cin >> n;
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= n; j++) {
            cin >> a[i][j];
        }
    }

    solve();

    return 0;
}

这个做法的重复计算比较多。
其实一个空位 (i,j) 的答案只由两件事决定:

  • i 行的总和
  • j 列的总和

所以我们可以先预处理:

  • row_sum[i]:第 i 行总敌人数
  • col_sum[j]:第 j 列总敌人数

这样每个空位的得分就能直接写成:

row_sum[i] + col_sum[j]

再在所有空位里取最大值即可。

因为空位本身是 0,这里不会有重复多算当前位置的问题。

代码

cpp
#include <bits/stdc++.h>
using namespace std;

const int MAXN = 1005;

int n;
int a[MAXN][MAXN];
int row_sum[MAXN];
int col_sum[MAXN];

void solve() {
    int ans = 0;

    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= n; j++) {
            if (a[i][j] == 0) {
                ans = max(ans, row_sum[i] + col_sum[j]);
            }
        }
    }

    cout << ans << '\n';
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    cin >> n;
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= n; j++) {
            cin >> a[i][j];
            row_sum[i] += a[i][j];
            col_sum[j] += a[i][j];
        }
    }

    solve();

    return 0;
}

复杂度

时间复杂度是 O(n2)O(n^2),空间复杂度是 O(n2)O(n^2)

总结

这题的关键在于把“每个空位的攻击结果”改写成“行和 + 列和”。

预处理完行列和之后,枚举空位就很直接了。