题目大意
给出一张
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,j−1+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={0f2i−1,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,j−3,因为在左、右、上、下 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;
}
文章介绍了在一个由.(空地)和#(障碍物)组成的网格中,如何使用预处理和状态转移方程(类似最长公共子串)计算在放置灯光后,光可以照亮的空地数量。通过定义四个方向的数组f1-f4来递推求解,最终减去重复计数得到答案。
1705

被折叠的 条评论
为什么被折叠?



