【悬线法】糖果盒

来源:互联网 发布:为什么淘宝商品不见了 编辑:程序博客网 时间:2024/05/17 03:57

Description一个被分为 n*m 个格子的糖果盒,第 i 行第 j 列位置的格子里面有 a [ i ][ j ] 颗糖。本来 tenshi 打算送这盒糖果给某 PPMM 的,但是就在要送出糖果盒的前一天晚上,一只极其可恶的老鼠夜袭糖果盒,有部分格子被洗劫并且穿了洞。tenshi 必须尽快从这个糖果盒里面切割出一个矩形糖果盒,新的糖果盒不能有洞,并且 tenshi 希望保留在新糖果盒内的糖的总数尽量多。请帮tenshi设计一个程序 计算一下新糖果盒最多能够保留多少糖果。Input从标准输入读入数据。第一行有两个整数 n、m。第 i + 1 行的第 j 个数表示 a [ i ][ j ],如果这个数为 0 ,则表示这个位置的格子被洗劫过。其中:1 ≤ n,m ≤ 10000 ≤ a [i][j]≤ 255Output输出最大糖果数到标准输出。Sample Input3 41 2 3 45 0 6 310 3 4 0Sample Output17 
悬线法求极大子矩形。
设L[j](按行滚动)为该列向左能达到的最远非障碍点;R[j](按行滚动)为该列向右能达到的最远费障碍点;H[j](按行滚动)为该列向上能达到的最远非障碍点。
再设maxL为该悬线(即该点与向上能达到的最远非障碍点的连线)向左最远能够平移的距离,maxR为该悬线向右最远能够平移的距离。那么左右平移的悬线就构成了一个矩形!
这样,枚举所有位置,选一个最大的矩形即可。

Accode:

#include <cstdio>#include <cstdlib>#include <string>using std::max; using std::min;const int maxN = 1010;int a[maxN][maxN], H[maxN], sum[maxN][maxN];int maxL[2][maxN], maxR[2][maxN];int L[maxN], R[maxN], n, m, ans;inline int getint(){    int res = 0; char tmp;    while (!isdigit(tmp = getchar()));    do res = (res << 3) + (res << 1) + tmp - '0';    while (isdigit(tmp = getchar()));    return res;}int main(){    freopen("candy.in", "r", stdin);    freopen("candy.out", "w", stdout);    n = getint(); m = getint();    for (int i = 1; i < n + 1; ++i)    for (int j = 1; j < m + 1; ++j)        sum[i][j] = sum[i][j - 1]            + (a[i][j] = getint());    for (int i = 1; i < n + 1; ++i)    for (int j = 1; j < m + 1; ++j)        sum[i][j] += sum[i - 1][j];    for (int j = 1; j < m + 1; ++j)        maxR[0][j] = m;    R[m + 1] = m;//这里要赋初值,否则出错。    for (int i = 1; i < n + 1; ++i)    {        int pst = (i & 1) ^ 1, ths = i & 1;        for (int j = 1; j < m + 1; ++j)        if (!a[i][j])            H[j] = i, L[j] = j, maxL[ths][j] = 0;//如果该行该列的点为障碍,//那么下一行的maxL值跟这一行无关,设为0。else        {            L[j] = L[j - 1];            maxL[ths][j] = max(L[j], maxL[pst][j]);        }        for (int j = m; j; --j)        if (!a[i][j])            R[j] = j - 1, maxR[ths][j] = m;//如果该行该列的点为障碍,//那么下一行的maxR值跟这一行无关,设为m。        else        {            R[j] = R[j + 1];            maxR[ths][j] = min(R[j], maxR[pst][j]);            int _L = maxL[ths][j], _R = maxR[ths][j],            _U = H[j];            ans = max(ans, sum[i][_R] + sum[_U][_L]                      - sum[i][_L] - sum[_U][_R]);        }    }    printf("%d\n", ans);    return 0;}