UVA836 Largest Submatrix【最大子段和+DP】

Let A be an N × N matrix of zeros and ones. A submatrix S of A is any group of contiguous entries that forms a square or a rectangle.
Write a program that determines the number of elements of the largest submatrix of ones in A. Largest here is measured by area.
Input
The input begins with a single positive integer on a line by itself indicating the number of the cases following, each of them as described below. This line is followed by a blank line, and there is also a blank line between two consecutive inputs.
The matrix is given line by line. Each line consists of 0’s and 1’s. The order of the matrix is also the number of lines input and 1 < N ≤ 25.
Output
For each test case, the output must follow the description below. The outputs of two
consecutive cases will be separated by a blank line.
The output is the number of elements of the largest submatrix found.
Sample Input
1

10111000
00010100
00111000
00111010
00111111
01011110
01011110
00011110
Sample Output
16

问题链接UVA836 Largest Submatrix
问题简述:给定一个nn的矩阵,矩阵元素只由0和1构成,找出只包含元素1的最大子矩阵。
问题分析
    将值为0的元素换为足够小的负数, 进行最大子矩阵进行计算即可。因为只要有足够大的元素在子矩阵中,其子矩阵和就变成负。
    另外一种做法是使用滑动窗口法来实现,时间复杂度是O(n
n),参见参考链接1实现。
    另外增加2种解法,使用了前缀和,时间复杂度是O(n^3),比暴力法好很多。
    RE的程序根据参考链接2的代码进行计算,RE的原因在哪里?不明白。
程序说明:(略)
参考链接
1.UVA1330 LA3029 POJ1964 HDU1505 City Game【最大子段和+DP】
2.UVA108 Maximum Sum【最大子段和+DP】
题记:(略)

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

/* UVA836 Largest Submatrix */

#include <bits/stdc++.h>

using namespace std;

const int N = 25;
int a[N][N], up[N][N], l[N][N], r[N][N];
char s[N + 1];

int main()
{
    int t;
    scanf("%d", &t);
    getchar();
    gets(s);
    while (t--) {
        int m = 0, n;
        while(gets(s) && s[0]) {
            n = strlen(s);
            for(int j = 0; j < n; j++)
                a[m][j] = 1 - (s[j] - '0');
            m++;
        }

        int ans = 0;
        for(int i = 0; i < m; i++) {
            int left = -1, right = n;
            for(int j = 0; j < n; j++) {
                if(a[i][j] == 1) {
                    up[i][j] = l[i][j] = 0;
                    left = j;
                } else {
                    up[i][j] = i == 0 ? 1 : up[i - 1][j] + 1;
                    l[i][j] = i == 0 ? left + 1 : max(l[i - 1][j], left + 1);
                }
            }
            for(int j = n - 1; j >= 0; j--)
                if(a[i][j] == 1) {
                    r[i][j] = m;
                    right= j;
                } else {
                    r[i][j] = i == 0 ? right - 1 : min(r[i - 1][j], right - 1);
                    ans = max(ans, up[i][j] * (r[i][j] - l[i][j] + 1));
                }
        }

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

    return 0;
}

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

/* UVA836 Largest Submatrix */

#include <bits/stdc++.h>

using namespace std;

const int N = 25;
int sum[N + 1][N + 1];
char s[N + 1];
const int M1000 = - (N + 1) * (N + 1);

int main()
{
    int t, a;
    scanf("%d", &t);
    getchar();
    gets(s);
    while (t--) {
        int i = 1, n;
        while(gets(s) && s[0]) {
            sum[i][0] = 0;
            n = strlen(s);
            for(int j = 1; j <= n; j++) {
                a = s[j - 1] == '1' ? 1 : M1000;
                sum[i][j] = sum[i][j - 1] + a;
            }
            i++;
        }

        // 滑动窗口法:按第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);
        if (t)  printf("\n");
    }
    return 0;
}

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

/* UVA836 Largest Submatrix */

#include <bits/stdc++.h>

using namespace std;

const int N = 25;
int sum[N + 1][N + 1], dp[N + 1];
char s[N + 1];
const int M1000 = - (N + 1) * (N + 1);

int main()
{
    int t, a;
    scanf("%d", &t);
    getchar();
    gets(s);
    while (t--) {
        int i = 1, n;
        while(gets(s) && s[0]) {
            sum[i][0] = 0;
            n = strlen(s);
            for(int j = 1; j <= n; j++) {
                a = s[j - 1] == '1' ? 1 : M1000;
                sum[i][j] = sum[i][j - 1] + a;
            }
            i++;
        }

        // 按第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);
        if (t)  printf("\n");
    }
    return 0;
}

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

/* UVA836 Largest Submatrix */

#include <bits/stdc++.h>

using namespace std;

const int N = 25;
int sum[N + 1][N + 1];
char s[N + 1];
const int M1000 = - (N + 1) * (N + 1);

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

        int i = 1, n;
        while(gets(s) && s[0]) {
            n = strlen(s);
            for(int j = 1; j <= n; j++) {
                a = s[j - 1] == '1' ? 1 : M1000;
                sum[i][j] = sum[i - 1][j] + sum[i][j - 1] - sum[i - 1][j - 1] + a;
            }
            i++;
        }

        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);
        if (t)  printf("\n");
    }
    return 0;
}

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

/* UVA836 Largest Submatrix */

#include <bits/stdc++.h>

using namespace std;

const int N = 25;
int a[N + 2][N + 2], sum[N + 2][N + 2];
char s[N + 1];
const int M1000 = - (N + 1) * (N + 1);

int main()
{
    int t;
    scanf("%d", &t);
    getchar();
    gets(s);
    while(t--) {
        memset(sum, 0, sizeof(sum));

        gets(s);
        int i = 1, n = strlen(s);
        while(s[0]) {
            for(int j = 1; j <= n; j++) {
                a[i][j] = s[j - 1] == '1' ? 1 : M1000;
                sum[i][j] = sum[i - 1][j] + sum[i][j - 1] - sum[i - 1][j - 1] + a[i][j];
            }
            gets(s);
            i++;
        }

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

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

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

猜你喜欢

转载自blog.csdn.net/tigerisland45/article/details/105341855