AtCoder ContextABC 129 D Lamp(路灯)

题目
运行时间限制: 2sec
内存限制: 1024MB

题目
有一个H行W列的格子区域。在这个格子区域里面,有些格子里面放置了障碍物。
小明会在这个格子区域里面,选择一个没有障碍物的小格子,在小格子里放置一盏灯。从放置灯的小格子里,会有光束从上下左右四个方向射出。这些光束会被其他格子里的障碍物挡住,也会被格子区域的边缘挡住。
光线可以穿过放置灯的小格子上,但是光线不能穿过放置障碍物的小格子。

小明需要怎让选择放置灯的小格子的位置来满足让尽可能多的小格子被光束穿过。

有H个长度为W的字符串。字符串表示为Si(1<=i<=H)。
Si的第j个字符(1<=j<=W)是'#'的话,那么格子区域的从上往下数第i行,从左往右数第j列的格子是有障碍物的。
Si的第j个字符(1<=j<=W)是'.'的话,那么格子区域的从上往下数第i行,从左往右数第j列的格子是没有障碍物的。

求最多可以有多少个格子被光束照亮。

要求

  • 1<=H<=2000
  • 1<=W<=2000
  • Si是由'#'和'.'组成的长度为W的字符串
  • Si(1<=i<=H)里面至少有一个'.'

输入
输入都以一下标准从命令行输入

H W
S1
.
.
SH

输出
输出最多能够照亮多少个格子

例1
输入

4 6
#..#..
.....#
....#.
#.#...

例1
输出

8

小明在从上往下第2行,从左往右第2列放上灯的话
从上往下第2行,从左往右1~5列的格子
从左往右第2列,从上往下1~4行的格子
总共8个格子,都能被照亮

例2
输入

8 8
..#...#.
....#...
##......
..###..#
...#..#.
##....#.
#...#...
###.#..#

例2
输出

13

解题思路

读懂题目

1.首先这里有一个格子盘,相当于一个围棋盘

2.围棋盘里面有几个格子里有障碍物

3.只有一盏灯

AtCoder ContextABC 129 D Lamp(路灯)_第1张图片
图1

解题思路

遍历每一个格子
当遍历到这个格子的时候,求每一个灯放在这个格子上的时候,所能照亮的范围有多大

如何求出遍历到每一个格子的时候,灯光所涵盖的范围
1.我们其实可以观察出来,每一个格子,光束照亮四个方向。
给定四个变量L,R,U,D
那么对于每一个格子来说
格子左边(包括格子自己)能照亮多少个格子的值赋予变量L
格子右边(包括格子自己)能够照亮多少个格子的值赋予变量R
格子上面(包括格子自己)能够照亮多少个格子的值赋予变量U
格子下面(包括格子自己)能够照亮多少个格子的值赋予变量D

如图1
L=2
U=2
R=4
D=3
L+U+R+D = 2+2+4+3 = 11
应为L,U,R,D都包括了格子自己,所以格子自己重复计算了4次,有三次重复计算是多余的所以最终结果是11-3=8

那么最终的公式result=L+U+R+D-3

如何求出L,U,R,D
如果这个时候分别遍历行和列,那么时间可能就不够了
这里要用到堆加计算的方法

AtCoder ContextABC 129 D Lamp(路灯)_第2张图片
图2

可以感觉得出来,
L的值就是左边格子的L的值+1,进而得出
Li = Li-1 + 1
同样
Ri = Ri+1 + 1
Ui = Ui-1 + 1
Di = Di+1 + 1

特殊情況
1.当格子是障碍物的时候
L,R,U,D的值都为0,因为障碍物灯光找不到
2.上边缘的时候,U=1,因为再上面没有格子了,光束只能通过自己
3.右边缘的时候,R=1,因为再右面没有格子了,光束只能通过自己
4.左边缘的时候,L=1,因为再左面没有格子了,光束只能通过自己
4.下边缘的时候,D=1,因为再下面没有格子了,光束只能通过自己

代码

#python达不到时间要求
#用pypy3提交
def calculate(h, w, arr):
    L = [[0]*w for i in range(h)]
    U = [[0]*w for i in range(h)]
    D = [[0]*w for i in range(h)]
    R = [[0]*w for i in range(h)]

    for ih in range(h):
        for iw in range(w):
            if ih == 0:
                U[ih][iw] = 1
            if iw == 0:
                L[ih][iw] = 1

            if arr[ih][iw] == 1:
                L[ih][iw] = 0
                U[ih][iw] = 0

            else:
                if iw > 0:
                    L[ih][iw] = L[ih][iw - 1] + 1
                if ih > 0:
                    U[ih][iw] = U[ih - 1][iw] + 1

            rih = h - 1 - ih
            riw = w - 1 - iw

            if rih == h - 1:
                D[rih][riw] = 1
            if riw == w - 1:
                R[rih][riw] = 1

            if arr[rih][riw] == 1:
                D[rih][riw] = 0
                R[rih][riw] = 0
            else:
                if riw < w - 1:
                    R[rih][riw] = R[rih][riw + 1] + 1
                if rih < h - 1:
                    D[rih][riw] = D[rih + 1][riw] + 1

    max = 0
    for ih in range(h):
        for iw in range(w):
            value = L[ih][iw] + R[ih][iw] + U[ih][iw] + D[ih][iw] - 3
            if value > max:
                max = value
    print(int(max))


S = input().split(" ")
H = int(S[0])
W = int(S[1])

arr = []
for i in range(H):
    q = input()
    tmp = []
    for qs in q:
        if qs == "#":
            tmp.append(1)
        if qs == ".":
            tmp.append(0)
    arr.append(tmp)

calculate(H, W, arr)

题外话

1.python3.4是达不到速度的要求的,所以在提交代码的时候,选择pypy3
2.pypy3不支持numpy,在构建空数组的时候,选用一下的方式

[[0]*w for i in range(h)]

你可能感兴趣的:(python)