【u126】矩形

Time Limit: 1 second
Memory Limit: 128 MB

【问题描述】

给出一个n*n的矩阵,矩阵中,有些格子被染成黑色,有些格子被染成黑色,现要求矩阵中白色矩形的数量。


【输入格式】

输入文件rec.in第一行,仅包含一个整数n,表示矩形的大小。 接下来n行,每行n个字符,这些字符为“W”或“B”。其中“W”表示白格,“B”表示黑格。

【输出格式】

输出文件rec.out仅包括一个正整数,为白色矩形数量

【数据规模】

对于30%的数据,n ≤ 50; 对于100%的数据,n ≤ 150;

Sample Input1

4
WWBW
BBWB
WBWW
WBWB


Sample Output1

15

【题解】

这题有比较特殊的技巧。

设f[i][j]表示(i,j)这个白砖下面有连续几个白砖。

对于枚举到的白砖(i,j),令L=f[i][j];

答案累加L。

然后令k=j+1.不断往右枚举。

L=min(L,f[i][k])。如果f[i][k]==0则停止递增k.

否则答案累加L。

然后枚举所有的白砖即可。

原理如下。下面的1表示白砖。


假设当前i=1,j=1;

L=f[1][1]==3;

答案先累加L == 3;(表示3个长度为1的砖。如下图)


然后往右。答案再累加L==3(表示3个长度为2宽为1的砖);


跳过其他的点

然后i=2,j=1;

L=f[2][1];

答案先累加L==2;(第一列,竖下来,2个宽度为1,长为2的矩形);

如下图:


然后i=2,j=2;

L=min(L,f[2][1]);然后L仍然等于2;

所以答案再累加上2.(两列,竖下来,2个宽度为2,长为2的矩形如下图)


跳过其他点。

然后i=3,j=1;

L=f[3][1] == 1;

答案先累加L==1;

表示一个长为1,高为3的矩形,如下图;


然后往右i=3,j=2;

L仍然为1.答案累加L。

表示一个宽为2,高为3的矩形。


特殊的。

对于下面这种情况。


当i=2,j=1时,往右枚举时。加上L=2.表示的是下图的情况。


通过以上例子。

如果某个砖块下面还有砖。(白)

那么在对上面的砖操作之后。比如还会对下面的砖进行操作。

然后我们在对下面的砖进行操作的时候。实际上就是在枚举上面那个砖的右下角。

再往下的i-2号砖,也是一样在枚举最上面那个砖的右下角。

然后最上面那个砖作为左上角。

特殊的。认为只有一块砖的矩形是由最上面那个砖自己构成左上和右下组成的。

所以我们在枚举最上面那块砖下面的砖的时候。如果往右递增答案了。就相当于扩展了

矩形的右下角。

然后枚举的左上到右下这样的矩形个数恰

好为min(左上角下面的矩形数,右下角下面的白矩形)

这个左上角是会发生变化的。

就像上面那个图一样。

【代码】

#include <cstdio>
#include <iostream>
#include <string>
#include <cstring>

using namespace std;

int n;
string s;
bool bo[151][151];
int f[151][151] = { 0 };

void input_data()
{
	memset(bo, false, sizeof(bo));
	scanf("%d", &n);
	for (int i = 1; i <= n; i++)
	{
		cin >> s;
		for (int j = 1; j <= n; j++) //是白色的就记录一下。
			if (s[j - 1] == 'W')
				bo[i][j] = true; //转换成bool型数组。
	}
}

int min(int x, int y) //返回x和y之间的最小值。
{
	return x > y ? y : x;
}

void get_ans()
{
	for (int i = 1;i <= n;i++) 
		for (int j = 1;j <= n;j++)
			if (bo[i][j]) //如果是白的砖
			{ //则求出其(包括其)下面有多少个砖
				int k = i;
				while (bo[k-1][j]) k--;
				f[i][j] = i - k + 1;
			}
	int ans = 0; //这是最后要输出的答案
	for (int i = 1;i <= n;i++)
		for (int j = 1;j <= n;j++)
			if (f[i][j] > 0) //如果这个转是白砖。
			{
				int l = f[i][j];
				ans += l; //先累加上答案。
				int k = j + 1; //往右移动。
				while (f[i][k] > 0) //如果还是大于0.则可以扩展右下角。
				{
					l = min(f[i][k], l);
					ans += l; //累加相应的矩形个数即可。
					k++;
				}
			}
	printf("%d\n", ans);
}

int main()
{
	//freopen("F:\\rush.txt", "r", stdin);
	//freopen("F:\\rush_out.txt", "w", stdout);
	input_data();
	get_ans();
	//fclose(stdin);
	//fclose(stdout);
	return 0;
}



 

转载于:https://www.cnblogs.com/AWCXV/p/7632319.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值