[ABC129D] Lamp 题解

文章介绍了在一个由.(空地)和#(障碍物)组成的网格中,如何使用预处理和状态转移方程(类似最长公共子串)计算在放置灯光后,光可以照亮的空地数量。通过定义四个方向的数组f1-f4来递推求解,最终减去重复计数得到答案。

题目大意

给出一张 h h h w w w 列只由 .# 组成的图,其中 . 代表空地,可以放东西,# 代表障碍物,不可放东西。

我们可以在任意一个 . 上放灯,灯可以照亮上下左右四个方向,即水平和竖直两条线,且当光碰到障碍物时停止传播。

求光可以照亮几个空地。

思路

因为光只能向 4 4 4 个方向传播,所以我们进行预处理每一个位置向 4 4 4 个方向能照亮几个空地。

定义 4 4 4 个数组 f 1 f1 f1 f 2 f2 f2 f 3 f3 f3 f 4 f4 f4 分别表示该位置向左、右、上、下 4 4 4 个方向可以照亮几个空地。

方法类似于最长公共子串,下面给出状态转移方程:

f 1 i , j = { 0 a i , j = # f 1 i , j − 1 + 1 a i , j = . f1_{i,j}=\begin{cases}0 & a_{i,j}= \# \\f1_{i,j-1}+1 & a_{i,j}= . \end{cases} f1i,j={0f1i,j1+1ai,j=#ai,j=.

f 2 i , j = { 0 a i , j = # f 2 i − 1 , j + 1 a i , j = . f2_{i,j}=\begin{cases}0 & a_{i,j}= \# \\f2_{i-1,j}+1 & a_{i,j}= . \end{cases} f2i,j={0f2i1,j+1ai,j=#ai,j=.

f 3 i , j = { 0 a i , j = # f 3 i , j + 1 + 1 a i , j = . f3_{i,j}=\begin{cases}0 & a_{i,j}= \# \\f3_{i,j+1}+1 & a_{i,j}= . \end{cases} f3i,j={0f3i,j+1+1ai,j=#ai,j=.

f 4 i , j = { 0 a i , j = # f 4 i + 1 , j + 1 a i , j = . f4_{i,j}=\begin{cases}0 & a_{i,j}= \# \\f4_{i+1,j}+1 & a_{i,j}= . \end{cases} f4i,j={0f4i+1,j+1ai,j=#ai,j=.

最后进行计算答案,对于每个位置 i , j i,j i,j,可以照亮的空地数为 f 1 i , j + f 2 i , j + f 3 i , j + f 4 i , j − 3 f1_{i,j}+f2_{i,j}+f3_{i,j}+f4_{i,j}-3 f1i,j+f2i,j+f3i,j+f4i,j3,因为在左、右、上、下 4 4 4 个方向上 i , j i,j i,j 这个空地被算了 4 4 4 次,实际上应该只算 1 1 1 次,所以要减 3 3 3

代码

#include<bits/stdc++.h>
using namespace std;
int h,w,f1[2010][2010],f2[2010][2010],f3[2010][2010],f4[2010][2010],ans;
char a[2010][2010];
int main()
{
	ios::sync_with_stdio(false);
	cin>>h>>w;
	for(int i=1;i<=h;i++) for(int j=1;j<=w;j++) cin>>a[i][j];//我这里写getchar挂掉了。 
	for(int i=1;i<=h;i++)
		for(int j=1;j<=w;j++)
			f1[i][j]=(a[i][j]=='.'?f1[i][j-1]+1:0),f3[i][j]=(a[i][j]=='.'?f3[i-1][j]+1:0);
	for(int i=h;i;i--)
		for(int j=w;j;j--)
			f2[i][j]=(a[i][j]=='.'?f2[i][j+1]+1:0),f4[i][j]=(a[i][j]=='.'?f4[i+1][j]+1:0);
	for(int i=1;i<=h;i++)
		for(int j=1;j<=w;j++)
			ans=max(ans,f1[i][j]+f2[i][j]+f3[i][j]+f4[i][j]-3);
	cout<<ans;
	return 0;
}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值