蓝桥杯-T字消除

"""
题目来源:
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)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

武科菜鸟

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值