HDU 1506 1505 2870 2830

原文链接: HDU 1506 1505 2870 2830

上一篇: CCF z型扫描

下一篇: 交通规划 ccf

1506 连续矩形最大面积

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>

#define LL long long
int const MAX = 1e6 + 1;
int const INF = 1 << 30;

using namespace std;

//分别记录第i个柱子的高度和左右能够延伸的最远的柱子

LL H[MAX], L[MAX], R[MAX];
int main(int argc, char*argv[]) {
    int n;

    while ( scanf("%d", &n) == 1 && n ) {
        for ( int i = 1; i <= n; i++ ) {
            scanf("%lld", H + i);
            L[i] = i;
            R[i] = i;
        }

        //由第2个开始更新左边,L[i]表示第i个矩形可以延伸到的最左边的柱子
        //L[i]-1 就是最左边柱子的左边
        for ( int i = 2; i <= n; i++ ) {
            while ( H[L[i] - 1] >= H[i] ) {
                L[i] = L[L[i] - 1];
                if ( L[i] == 1 )
                    break;
            }

        }

        //更新右边由n-1个开始,R[i]表示第i个矩形可以延伸的最右边的柱子
        for ( int i = n - 1; i >= 1; i-- )
            while ( H[R[i] + 1] >= H[i] ) {
                R[i] = R[R[i] + 1];
                if ( R[i] == n )
                    break;
            }

        LL ans = -1;
        for ( int i = 1; i <= n; i++ ) {
            LL t = ( R[i] - L[i] + 1 ) * H[i];
            if ( t > ans )
                ans = t;
        }
        printf("%lld\n", ans);

    }

    return 0;
}

1505

题目大意:给出一个n * m 的矩形,求全为F的矩形面积最大。
题目思路:这道题和HDU1506很像。
d[i][j]表示第i行j列元素在前i行中的最大高度。(以第一行为底)例如测试样例:
09134206_9J2e.jpg
然后和HDU-1506思路一样,
找出以当前点位最低点能左右延伸的最长距离,也就是找出最左最右的下标,最后的 ans = max(num[i]*(r[i]-l[i]+1))

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>

#define LL long long
int const MAX = 1111;
int const INF = 1 << 30;

using namespace std;

int mp[MAX][MAX], L[MAX], R[MAX], H[MAX][MAX];
int n, m;

int main(int argc, char*argv[]) {
    int T;

    scanf("%d", &T);
    while ( T-- ) {

        scanf("%d%d", &n, &m);

        char s[3];
        for ( int i = 1; i <= n; i++ )
            for ( int j = 1; j <= m; j++ ) {
                scanf("%s", s);
                //F代表可用,设为1,方便计算高度
                if ( s[0] == 'F' ) mp[i][j] = 1;
                else mp[i][j] = 0;
            }

        //计算每行点的高度和左右最长可延伸的位置,类似1506
        for ( int i = 1; i <= n; i++ ) {
            //计算第i行第j列的高度
            for ( int j = 1; j <= m; j++ ) {
                //如果不可用
                if ( mp[i][j] == 0 ) H[i][j] = 0;
                //可以使用滚动数组
                else H[i][j] = H[i - 1][j] + 1;
            }
        }

/*
        for ( int i = 1; i <= n; i++ ) {
            for ( int j = 1; j <= m; j++ )
                printf("%d  ", H[i][j]);
            printf("\n");
        }
 */
        //对每一行使用1506的做法进行计算
        int ans = -1;
        for ( int i = 1; i <= n; i++ ) {
            //计算左边
            for ( int j = 1; j <= m; j++ )
                L[j] = R[j] = j;

            for ( int j = 2; j <= m; j++ ) {
                while ( H[i][L[j] - 1] >= H[i][j] ) {
                    L[j] = L[L[j] - 1];
                    if ( L[j] == 1 )
                        break;
                }
            }
            //计算右边

            for ( int j = m - 1; j >= 1; j-- ) {
                while ( H[i][R[j] + 1] >= H[i][j] ) {
                    R[j] = R[R[j] + 1];
                    if ( R[j] == m )
                        break;
                }

            }
/*
            for ( int j = 1; j <= m; j++ )
                printf("%d ", L[j]);
            printf("\n");
            for ( int j = 1; j <= m; j++ )
                printf("%d ", R[j]);
            printf("\n");
 */
            //计算总的
            for ( int j = 1; j <= m; j++ ) {
                int t = ( R[j] - L[j] + 1 ) * H[i][j];
                if ( t > ans )
                    ans = t;
            }

        }

        printf("%d\n", ans * 3);

    }

    return 0;
}

2830

分析:扫描每一行,以该行作为底,用dp存放每一列1达到的高度,然后将高度排序(当然,不能直接对dp排序,因为扫下一行的有用),很容易就能找出最大的面积.最后就可以找出整体的最大值了

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>

#define LL long long
int const MAX = 1111;
int const INF = 1 << 30;

using namespace std;
int mp[MAX][MAX], H[MAX][MAX], L[MAX], R[MAX];
int n, m;
void show() {
    for ( int i = 1; i <= n; i++ ) {
        for ( int j = 1; j <= m; j++ )
            printf("%d ", mp[i][j]);
        printf("\n");
    }
    for ( int i = 1; i <= n; i++ ) {
        for ( int j = 1; j <= m; j++ )
            printf("%d ", H[i][j]);
        printf("\n");
    }
}

int main(int argc, char*argv[]) {


    while ( scanf("%d %d", &n, &m) == 2 ) {
        char s[1111];
        for ( int i = 1; i <= n; i++ ) {
            scanf("%s", s + 1);
            for ( int j = 1; j <= m; j++ )
                mp[i][j] = s[j] - '0';
        }

        for ( int i = 1; i <= n; i++ )
            for ( int j = 1; j <= m; j++ ) {
                if ( mp[i][j] == 1 ) H[i][j] = H[i - 1][j] + 1;
                else H[i][j] = 0;
            }

        // show();
        //先按照高度排序,再对每一行使用1505的方法即可
        int ans = -1;
        for ( int i = 1; i <= n; i++ ) {

            for ( int j = 1; j <= m; j++ )
                L[j] = R[j] = j;
            sort(&H[i][1], &H[i][m] + 1);

            //计算左边
            for ( int j = 2; j <= m; j++ ) {
                while ( H[i][L[j] - 1] >= H[i][j] ) {
                    L[j] = L[L[j] - 1];
                    if ( L[j] == 1 )
                        break;
                }

            }
            //计算右边
            for ( int j = m - 1; j >= 1; j-- ) {
                while ( H[i][R[j] + 1] >= H[i][j] ) {
                    R[j] = R[R[j] + 1];
                    if ( R[j] == m )
                        break;
                }

            }

            //计算总和
            for ( int j = 1; j <= m; j++ ) {
                int t = ( R[j] - L[j] + 1 ) * H[i][j];
                ans = max(t, ans);
            }
        }
        printf("%d\n", ans);

    }

    return 0;
}

2870

题意: 一个由字符a,b,c,w,x,y,z组成的矩阵,其中w,x,y,z可以转换成a,b,c中的某几个字符,问该矩阵可以组成的由相同字符构成的最大子矩阵。

分析: DP。首先想到要求的子矩阵一定是由相同字符构成的,所以可以枚举w,x,y,z分别转换成a,b,c后得到的最大子矩阵即可。

枚举最大矩形是由哪个字母构成的

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>

#define LL long long
int const MAX = 1111;
int const INF = 1 << 30;

using namespace std;
int n, m;
char mp[MAX][MAX];
int H[MAX][MAX], L[MAX], R[MAX];
int ans = -1;

//根据不同的字母计算出的H,计算最大值
void dp() {
    for ( int i = 1; i <= n; i++ ) {
        //计算左边
        for ( int j = 1; j <= m; j++ )
            L[j] = R[j] = j;

        for ( int j = 2; j <= m; j++ ) {
            while ( H[i][L[j] - 1] >= H[i][j] ) {
                L[j] = L[L[j] - 1];
                if ( L[j] == 1 )
                    break;
            }
        }
        //计算右边

        for ( int j = m - 1; j >= 1; j-- ) {
            while ( H[i][R[j] + 1] >= H[i][j] ) {
                R[j] = R[R[j] + 1];
                if ( R[j] == m )
                    break;
            }

        }
        /*
            for ( int j = 1; j <= m; j++ )
                printf("%d ", L[j]);
            printf("\n");
            for ( int j = 1; j <= m; j++ )
                printf("%d ", R[j]);
            printf("\n");
         */
        //计算总的
        for ( int j = 1; j <= m; j++ ) {
            int t = ( R[j] - L[j] + 1 ) * H[i][j];
            ans = max(ans, t);
        }

    }
}
int main(int argc, char*argv[]) {
    while ( scanf("%d %d", &n, &m) == 2 ) {
        ans = -1;
        for ( int i = 1; i <= n; i++ )
            scanf("%s", mp[i] + 1);

        //由a构成
        for ( int i = 1; i <= n; i++ ) {
            for ( int j = 1; j <= m; j++ ) {
                if ( mp[i][j] == 'a' || mp[i][j] == 'w' || mp[i][j] == 'y' || mp[i][j] == 'z' ) {
                    H[i][j] = H[i - 1][j] + 1;
                } else {
                    H[i][j] = 0;
                }
            }
        }
        dp();
        for ( int i = 1; i <= n; i++ ) {
            for ( int j = 1; j <= m; j++ ) {
                if ( mp[i][j] == 'c' || mp[i][j] == 'x' || mp[i][j] == 'y' || mp[i][j] == 'z' ) {
                    H[i][j] = H[i - 1][j] + 1;
                } else {
                    H[i][j] = 0;
                }
            }
        }
        dp();
        for ( int i = 1; i <= n; i++ ) {
            for ( int j = 1; j <= m; j++ ) {
                if ( mp[i][j] == 'b' || mp[i][j] == 'w' || mp[i][j] == 'x' || mp[i][j] == 'z' ) {
                    H[i][j] = H[i - 1][j] + 1;
                } else {
                    H[i][j] = 0;
                }
            }
        }
        dp();
        printf("%d\n", ans);
    }

    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值