UVa 1330 City Game(DP)

1 篇文章 0 订阅

题目链接:
https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=4076

题目大意:求出给定二位矩阵中的最大的子矩阵的面积;

解析:这题实际上有点像二维DP,对与任意一个位置的[i][j]维护它的上方高度,左侧与右侧有效的可达到的位置。转移方程如下:([i][j]为空位置)height[i][j] = height[i-1][j] + 1; leftmarker[i][j] = max(left[i-1][j], leftbo + 1); rightmarker = min(rightmarker[i-1][j], rightbo - 1)。

这里leftmarker[i][j]与rightmarker[i][j]与上一行的同样列的数值是有很大关系的,不能直接用得到的左侧和右侧的最近的非空位置作为左右侧可达到的有效位置。


AC代码如下:

#include <iostream>
#pragma comment(linker, "/STACK:1024000000,1024000000") 
#include <stdio.h>
#include <fstream>
#include <iomanip>
#include <cmath>
#include <string>
#include <string.h>
#include <sstream>
#include <cctype>
#include <climits>
#include <set>
#include <map>
#include <deque>
#include <queue>
#include <vector>
#include <iterator>
#include <algorithm>
#include <stack>
#include <functional>
//cout << "OK" << endl;
#define _clr(x,y) memset(x,y,sizeof(x))
#define _inf(x) memset(x,0x3f,sizeof(x))
#define pb push_back
#define mp make_pair
#define FORD(i,a,b) for (int i=(a); i<=(b); i++)
#define FORP(i,a,b) for (int i=(a); i>=(b); i--)
#define REP(i,n) for (int i=0; i<(n); i++)
using namespace std;
const int INF = 0x3f3f3f3f;
const double eps = 1e-8;
const double EULER = 0.577215664901532860;
const double PI = 3.1415926535897932384626;
const double E = 2.71828182845904523536028;
typedef long long LL;
LL pow_mod(LL a,LL n,LL m)
{
    if(n == 0) return 1;
    LL x = pow_mod(a,n>>1,m);
    LL ans = x*x%m;
    if(n&1) ans = ans*a%m;
    return ans;
}
int gcd(int a,int b){return b == 0 ? a : gcd(b,a%b);}

#define N 1010  
int data[N][N], height[N][N], leftmarker[N][N], rightmarker[N][N]; 
int main(){
    int t;
    cin >> t;
    while(t--){
        int n,m;
        cin >> n >> m;
        getchar();
        //这里尤其要注意输入的方法,应该不断读入单个字符,并在为R或F的时候进行判断
        //0代表不空,1代表空 
        FORD(i,0,n-1){
            FORD(j,0,m-1){
                char ch = getchar();  
                while (ch != 'F'&&ch != 'R')ch = getchar();  
                data[i][j] = ch == 'F' ? 1 : 0;  
            }
        }

//      FORD(i,0,n-1){
//          FORD(j,0,m-1){
//              cout << data[i][j] << " ";
//          }
//          cout << endl;
//      }

        //这里从上而下,维护每一个点的上部最大空间,可到达的有效的左侧与右侧的位置 
        FORD(i,0,n-1){
            int leftbo = -1;
            int rightbo = m;
            FORD(j,0,m-1){
                if(data[i][j]){
                    //如果是空的,那么在第一行的时候特别处理
                    //其余时候,参考转移方程 
                    if(i == 0){
                        height[i][j] = 1;
                        leftmarker[i][j] = leftbo + 1;
                    }
                    else{
                        height[i][j] = height[i-1][j] + 1;
                        leftmarker[i][j] = max(leftmarker[i-1][j], leftbo + 1);
                    }
                }
                else{
                    //如果当前点不空,高度显然为0,左侧可到达位置变为0列
                    height[i][j] = 0;
                    leftmarker[i][j] = 0;
                    leftbo = j;
                }
            }
            //同理,处理右侧可达到位置 
            FORP(j,m-1,0){
                if(data[i][j]){
                    if(i == 0) rightmarker[i][j] = rightbo - 1;
                    else rightmarker[i][j] = min(rightmarker[i-1][j], rightbo - 1);
                }
                else{
                    rightmarker[i][j] = m - 1;
                    rightbo = j;
                }
            }
        }

        int ans = 0;
        FORD(i,0,n-1){
            FORD(j,0,m-1){
                if(data[i][j]){
                    ans = max(ans, height[i][j] * (rightmarker[i][j] - leftmarker[i][j] + 1));
                }
            }
        }
        cout << ans*3 << endl;
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值