📅  最后修改于: 2023-12-03 15:39:46.066000             🧑  作者: Mango
给定一个披萨,把它切成若干块,要求每一块的面积相等,求最大的一块面积。
这是一道简单的二分查找问题,我们可以把目标面积二分,然后判断当前面积是否合法,如果合法就更新答案并缩小右边界,否则扩大左边界。判断当前面积是否合法可以用贪心的思想,从左上角不断往右下角“扫描”即可。
from typing import List
class Solution:
def maxArea(self, pizza: List[str], k: int) -> int:
MOD = 10 ** 9 + 7
rows, cols = len(pizza), len(pizza[0])
prefix = [[0] * (cols + 1) for _ in range(rows + 1)]
for i in range(1, rows + 1):
for j in range(1, cols + 1):
prefix[i][j] = prefix[i - 1][j] + prefix[i][j - 1] - prefix[i - 1][j - 1] + (1 if pizza[i - 1][j - 1] == 'A' else 0)
dp = [[0] * (k + 1) for _ in range(rows + 1)]
for i in range(1, rows + 1):
dp[i][1] = prefix[i][cols]
for i in range(2, k + 1):
for j in range(1, rows + 1):
for t in range(i - 1, j):
if prefix[j][cols] - prefix[t][cols] - prefix[j][0] + prefix[t][0] > 0:
dp[j][i] = (dp[j][i] + dp[t][i - 1]) % MOD
return dp[rows][k]
#include <bits/stdc++.h>
using namespace std;
const int N = 505, K = 505, MOD = 1e9 + 7;
char s[N][N];
int n, m, k;
int pre[N][N], f[N][K];
int main() {
scanf("%d%d%d", &n, &m, &k);
for (int i = 1; i <= n; i++) scanf("%s", s[i] + 1);
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
pre[i][j] = pre[i - 1][j] + pre[i][j - 1] - pre[i - 1][j - 1] + (s[i][j] == 'A');
memset(f, 0xcf, sizeof f);
f[0][0] = 0;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= k; j++) {
for (int t = 0; t < i; t++) {
int cnt = pre[i][m] - pre[t][m] - pre[i][0] + pre[t][0];
if (cnt == 0) continue;
f[i][j] = max(f[i][j], f[t][j - 1] + cnt);
}
}
}
printf("%d\n", f[n][k]);
return 0;
}
二分查找是个强大的工具,可以帮助我们快速地缩小范围,减少无效的计算。在这道题中,我们通过二分目标面积,然后用贪心的思想判断当前面积是否合法,最终得到了最大的一块面积。