UVA10667 Largest Block【最大子段和+DP】

Consider a n × n chessboard. The term block(r1, c1, r2, c2) denotes the rectangular subset of squares defined by the intersection of rows {r1, r1 + 1, . . . , r2} and columns {c1, c1 + 1, . . . , c2}.
    There are several occupied blocks on the board. We are interested in the largest block (in the sense of maximum area) that can be placed in the free space remaining in the board.
    For example, in a chessboard of size 10, if block(2, 2, 5, 3), block(8, 3, 9, 7), and block(3, 6, 3, 8) represent occupied space, then the largest block that can be placed in free space has area 28. This can be visually checked in the following figure:
在这里插入图片描述
We are interested only in the area of the largest free block, and not in its particular location. Therefore, each instance of the problem has a unique solution.
Input
The program first reads the number p of instances of the problem. Each instance is described by the size s of the board, the number b of blocks of occupied space, and the vertices r1, c1, r2, c2, of each block:
在这里插入图片描述
Assumptions:
• 1 ≤ s ≤ 100
• 0 ≤ b ≤ 100
• 1 ≤ r1 ≤ r2 ≤ s
• 1 ≤ c1 ≤ c2 ≤ s
• Occupied blocks may overlap.
Output
For each test case the output consists of a integer indicating the area of the largest block that can be located in the available free squares.
Sample Input
3
10
3
2 2 5 3
8 3 9 7
3 6 3 8
20
1
1 1 1 1
10
2
5 1 5 10
1 5 10 5
Sample Output
28
380
25

问题链接UVA10667 Largest Block
问题简述:给定p*p棋盘,并且给定障碍区域数目,每个障碍区以两个点坐标形式确定,计算最大可用区域面积。
问题分析
    用最大子段和算法实现。
    用矩阵表示棋盘,开始时矩阵元素置为1,将障碍区域的各个元素置为足够小的负数, 进行最大子矩阵进行计算即可。因为只要有足够大的元素在子矩阵中,其子矩阵和就变成负。
    早先的解法时间复杂度过大,增加2种时间复杂度小的解法,参见参考链接。
程序说明:(略)
参考链接HDU1081 POJ1050 LA2288 To The Max【最大子段和+DP+滑动窗口法】
题记:(略)

AC的C++语言程序(前缀和+滑动窗口法)如下:

/* UVA10667 Largest Block */

#include <bits/stdc++.h>

using namespace std;

const int N = 100;
int a[N + 1][N + 1], sum[N + 1][N + 1];
const int M1000 = - (N + 1) * (N + 1);

int main()
{
    int t, n, b;
    scanf("%d", &t);
    while(t--) {
        memset(a, 0, sizeof(a));
        memset(sum, 0, sizeof(sum));

        scanf("%d%d", &n, &b);
        for(int i = 1; i <= n; i++)
            for(int j = 1; j <= n; j++)
                a[i][j] = 1;
        while(b--) {
            int r1, c1, r2, c2;
            scanf("%d%d%d%d", &r1, &c1, &r2, &c2);
            for(int i = r1; i <= r2; i++)
                for(int j = c1; j <= c2; j++)
                    a[i][j] = M1000;
        }

        for(int i = 1; i <= n; i++) {
            sum[i][0] = 0;
            for(int j = 1; j <= n; j++)
                sum[i][j] = sum[i][j - 1] + a[i][j];
        }

        // 滑动窗口法:按第i-j列,对所有的行计算最大子段和
        int maxSum = 0;
        for(int i = 1; i <= n; i++)
            for(int j = i; j <= n; j++) {
                int subSum = 0;
                for(int k = 1; k <= n; k++) {
                    subSum += sum[k][j] - sum[k][i - 1];
                    if(subSum > maxSum) maxSum = subSum;
                    if(subSum < 0) subSum = 0;
                }
            }

        printf("%d\n", maxSum);
    }

    return 0;
}

AC的C++语言程序(前缀和+DP)如下:

/* UVA10667 Largest Block */

#include <bits/stdc++.h>

using namespace std;

const int N = 100;
int a[N + 1][N + 1], sum[N + 1][N + 1], dp[N + 1];
const int M1000 = - (N + 1) * (N + 1);

int main()
{
    int t, n, b;
    scanf("%d", &t);
    while(t--) {
        memset(a, 0, sizeof(a));
        memset(sum, 0, sizeof(sum));

        scanf("%d%d", &n, &b);
        for(int i = 1; i <= n; i++)
            for(int j = 1; j <= n; j++)
                a[i][j] = 1;
        while(b--) {
            int r1, c1, r2, c2;
            scanf("%d%d%d%d", &r1, &c1, &r2, &c2);
            for(int i = r1; i <= r2; i++)
                for(int j = c1; j <= c2; j++)
                    a[i][j] = M1000;
        }

        for(int i = 1; i <= n; i++) {
            sum[i][0] = 0;
            for(int j = 1; j <= n; j++)
                sum[i][j] = sum[i][j - 1] + a[i][j];
        }

        // 按第i-j列,对所有的行计算最大子段和
        int ans = 0;
        for(int i = 1; i <= n; i++)
            for(int j = i; j <= n; j++) {
                memset(dp, 0, sizeof(dp));
                for(int k = 1; k <= n; k++) {
                    if(dp[k - 1] > 0)
                        dp[k] = dp[k - 1] + (sum[k][j] - sum[k][i - 1]);
                    else
                        dp[k] = sum[k][j] - sum[k][i - 1];
                    ans = max(ans, dp[k]);
                }
            }

        printf("%d\n", ans);
    }

    return 0;
}

AC的C++语言程序如下:

/* UVA10667 Largest Block */

#include <bits/stdc++.h>

using namespace std;

const int N = 100;
int a[N + 1][N + 1], sum[N + 1][N + 1];
const int M1000 = - (N + 1) * (N + 1);

int main()
{
    int t, n, b;
    scanf("%d", &t);
    while(t--) {
        memset(a, 0, sizeof(a));
        memset(sum, 0, sizeof(sum));

        scanf("%d%d", &n, &b);
        for(int i = 1; i <= n; i++)
            for(int j = 1; j <= n; j++)
                a[i][j] = 1;
        while(b--) {
            int r1, c1, r2, c2;
            scanf("%d%d%d%d", &r1, &c1, &r2, &c2);
            for(int i = r1; i <= r2; i++)
                for(int j = c1; j <= c2; j++)
                    a[i][j] = M1000;
        }

        for(int i = 1; i <= n; i++)
            for(int j = 1; j <= n; j++)
                sum[i][j] = sum[i - 1][j] + sum[i][j - 1] - sum[i - 1][j - 1] + a[i][j];

        int ans = 0;
        for (int i = 1; i <= n; i++)
            for (int j = 1; j <= n; j++)
                for (int p = i; p <= n; p++)
                    for (int q = j; q <= n; q++) {
                        int t = sum[p][q] - sum[p][j - 1] - sum[i - 1][q] + sum[i - 1][j - 1];
                        ans = max(ans, t);
                    }

        printf("%d\n", ans);
    }

    return 0;
}
发布了2289 篇原创文章 · 获赞 2373 · 访问量 265万+

猜你喜欢

转载自blog.csdn.net/tigerisland45/article/details/105354623
今日推荐