"""
题目来源:
https://www.lanqiao.cn/problems/3547/learning/?page=1&first_category_id=1&name=T%E5%AD%97%E6%B6%88%E9%99%A4
"""
import os
import sys
# 请在此输入您的代码
inf = 1000000000
# 获得a[x][y]的值
def get(a, x, y):
# 越界的话返回-1
if x < 0 or x >= len(a) or y < 0 or y >= len(a):
return -1
return int(a[x][y])
# 获取十字区域内点(x, y)的值
# 如果(x, y)越界了就返回inf, 否则就返回真实的值
def getin(a, x, y):
t = get(a, x, y)
if t == -1:
return inf
return t
# 如果a[x][y]=1或者(x, y)越界了就返回True
# 如果a[x][y]=0就返回False
def getout(a, x, y):
t = get(a, x, y)
if t == 0:
return False
return True
def solve(a, x, y):
"""
1.sum_1: 计算以(x, y)为中心的十字消除区域内1的个数
2.十字区域的消除的代价=sum_1 - 2, 不过需要考虑十字区域可能会有一部分越界, 则daijia_1 = sum_1 - mxm - 1,
"""
sum_1 = get(a, x, y)
mxm = 0
for i in [-1, 0, 1]:
for j in [-1, 0, 1]:
# 在以(x, y)为中心的十字区域内
if abs(i) + abs(j) == 1:
t = getin(a, x + i, y + j)
sum_1 += t
mxm = max(mxm, t)
# 代价可能为负值, 比如十字区域内全部为0的情况, 此时代价 = 0 - 2 = -2, 对于这种情况事实上不需要进行消除, 也就是代价也为0。
# 或者十字区域最上面的区域越界了, 其他区域为0, 此时代价是inf - mxm - 1 = inf - inf - 1 = -1, 消除代价也是为0。
daijia_1 = max(0, sum_1 - mxm - 1)
"""
2.判断在与中心(x, y)的曼哈顿距离为2或者3的区域内是否全部不为0。
曼哈顿距离: 比如(-3, 9)与中心(1, 3)的曼哈顿距离为abs(-3 - 1) + abs(9 - 1) == 12。
all(lis): 只要lis中有1个False(意思只要距离中心(x, y)的曼哈顿距离为2~3的区域内有一个0), 那么flag=False, 转为整型也就是0。
"""
flag = all([getout(a, x + i, y + j) for i in [-2, -1, 0, 1, 2] for j in [-2, -1, 0, 1, 2] if 2 <= abs(i) + abs(j) <= 3])
daijia_2 = int(flag)
"""
在进行一次十字消除后我们得到了一个全部为0的十字区域, 其T字消除的代价为max(0, sum_1 - mxm - 1)。
然后只要在与十字区域中心(x, y)的曼哈顿距离为2或者3的区域内找到一个0, 再配合全部为0的十字区域进行
一次T字消除, 可以明显看出所要消除的T字区最多只有一个1, 那么此次T字消除的代价为0。经过一次十字消除
和一次T字消除我们就可以得到一个2 * 2的全部为0区域, 那么后面每一次T字消除的代价都是最小的, 都为0。
所以我们需要求解是: 以哪中心点开始消除, 才能够让第一次的十字消除和第二次T字消除的代价和最小, 因为
后面的每次消除的代价都为0, 不需要考虑。
"""
return max(0, daijia_1) + daijia_2
D = int(input())
for _ in range(D):
n = int(input())
A = [input() for _ in range(n)]
# A中1的个数
sum_1 = sum(int(c) for s in A for c in s)
# T字消除的代价 = T字区域中有1的个数 - 1
ans = inf
for i in range(n):
for j in range(n):
ans = min(ans, solve(A, i, j))
# 操作的次数
count = sum_1 - ans
print(count)
蓝桥杯-T字消除
于 2024-03-24 23:19:14 首次发布