HDU 1505 City Game

传送门

直方图dp二维版本。
给你一个N*M的网格,每个格子有两种状态(R,F),让你在其中找一个面积最大的全部由F组成的矩形。

思路就是把每一行都当作每次直方图dp的底边,执行N次直方图dp,取最大值。
某一行某一列的柱子的高度可以看成从当前网格出发向上,碰到第一个R为止(不包括),有几个连续的F(包括自己)。若当前网格就是R,那么当前柱子高度就是0

网格是一行行输入的,若当前行当前列是F,那么具体的高度值可以由上一行当前列的值传递下来。

最后,这个题的输入很烦,是一个字符矩阵,每读取一个字符都要考虑这个字符之前有没有换行和空格。可以看出每行行首的字符前都会有一个换行,每行非行首的字符前都会有一个空格。代码中有两种读取形式,一种AC一种WA。我并不知道为什么。


#include <cstdio>
#include <iostream>
#include <algorithm>
#include <vector>
#include <cstring>
#include <string>
#include <queue>
using namespace std;                           // 直方图dp二维版

const int MAXN = 1001;
int M, N, T;
int g[MAXN][MAXN];                             // 表示第i行第j列的元素向上数有几个连续的F(包括自己,碰到第一个R为止)
int l[MAXN], r[MAXN];
int ans;

void init()
{
	for (int i = 1; i <= M; i++)               // 第1行i-1=0,用到了第0行的临界数据
		g[0][i] = 0;
	ans = -1;
}

int main()
{
	char c;
	scanf("%d", &T);
	for (; T--;)
	{
		scanf("%d%d", &N, &M);
		init();
		for (int i = 1; i <= N; i++)
		{
			for (int j = 1; j <= M; j++)
			{
				if (j == 1) scanf("\n%c", &c);
				else scanf(" %c", &c);                 // 这样写就AC

				//getchar();
				//scanf("%c", &c);                     // 这样就WA,我就想问,这两种有什么区别?

				if (c == 'R') g[i][j] = 0;
				else g[i][j] = g[i - 1][j] + 1;        // 可以从上往下传递,上一行的当前位置是R(0)就说明要从本行算起
			}
		}

		for (int i = 1; i <= N; i++)                   // 每一行可看成一个直方图dp
		{
			int t;
			l[1] = 1;
			for (int j = 2; j <= M; j++)
			{
				for (t = j; t - 1 >= 1 && g[i][t - 1] >= g[i][j]; t = l[t - 1]);
				l[j] = t;
			}
			r[M] = M;
			for (int j = M - 1; j >= 1; j--)
			{
				for (t = j; t + 1 <= M && g[i][t + 1] >= g[i][j]; t = r[t + 1]);
				r[j] = t;
			}
			for (int j = 1; j <= M; j++)
			{
				ans = max(ans, g[i][j] * (r[j] - l[j] + 1));   // 即使全是R,但因为高度都是0,所以直接把初始的-1覆盖掉了
			}
		}
		printf("%d\n", ans * 3);
	}

	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值