洛谷 P2701 [USACO5.3]巨大的牛棚Big Barn
Description
农夫约翰想要在他的正方形农场上建造一座正方形大牛棚。他讨厌在他的农场中砍树,想找一个能够让他在空旷无树的地方修建牛棚的地方。我们假定,他的农场划分成 N x N 的方格。输入数据中包括有树的方格的列表。你的任务是计算并输出,在他的农场中,不需要砍树却能够修建的最大正方形牛棚。牛棚的边必须和水平轴或者垂直轴平行。
EXAMPLE
考虑下面的方格,它表示农夫约翰的农场,‘.'表示没有树的方格,‘#'表示有树的方格
1 2 3 4 5 6 7 8
1 . . . . . . . .
2 . # . . . # . .
3 . . . . . . . .
4 . . . . . . . .
5 . . . . . . . .
6 . . # . . . . .
7 . . . . . . . .
8 . . . . . . . .
最大的牛棚是 5 x 5 的,可以建造在方格右下角的两个位置其中一个。
Input
Line 1: 两个整数: N (1 <= N <= 1000),农场的大小,和 T (1 <= T <= 10,000)有树的方格的数量
Lines 2..T+1: 两个整数(1 <= 整数 <= N), 有树格子的横纵坐标
Output
- 只由一行组成,约翰的牛棚的最大边长。
Sample Input
8 3 2 2 2 6 6 3
Sample Output
5
题解:
- dp。
- 设dp(i, j)为:以(i, j)为正方形右下角时最长的正方形边长。
- 设l(i, j)为以(i, j)为中心,向左拓展,最多能拓展到的点个数。
- 设r(i, j)为以(i, j)为中心,向上拓展,最多能拓展到的点个数。
- l和r数组可以先通过递推算出。至于dp怎么算,这样↓
- dp(i, j) = min { dp(i - 1, j - 1) + 1, l(i, j) + r(i, j) }
- 想象一下,如果dp(i - 1, j - 1)是最小,那么l,r肯定比它大。那么i这一行,j这一列上的,且在dp(i - 1, j - 1)范围中的格子肯定是合法的;如果l是最小的,那么dp,r都比它大。那么框定的正方形内肯定是合法的。
- 欸这用语言表达真的难,强烈建议个人脑中模拟出图形样子!
#include <iostream> #include <cstdio> #define N 1005 using namespace std; int n, m, ans; int a[N][N], dp[N][N], l[N][N], r[N][N]; int main() { cin >> n >> m; for(int i = 1; i <= m; i++) { int x, y; scanf("%d%d", &x, &y); a[x][y] = 1; } for(int i = 1; i <= n; i++) for(int j = 1; j <= n; j++) if(a[i][j]) l[i][j] = r[i][j] = 0; else l[i][j] = l[i][j - 1] + 1, r[i][j] = r[i - 1][j] + 1; for(int i = 1; i <= n; i++) for(int j = 1; j <= n; j++) { dp[i][j] = min(dp[i - 1][j - 1] + 1, min(l[i][j], r[i][j])); ans = max(ans, dp[i][j]); } cout << ans; return 0; }