[蓝桥杯 2024 省 Python B] 连连看 暴力解及正解

题目描述

小蓝正在和朋友们玩一种新的连连看游戏。在一个 n×m 的矩形网格中,每个格子中都有一个整数,第 i 行第 j 列上的整数为 Ai,j​。玩家需要在这个网格中寻找一对格子 (a,b) 和 (c,d) 使得这两个格子中的整数 Aa,b​ 和 Ac,d​ 相等,且它们的位置满足 ∣a−c∣=∣b−d∣>0。请问在这个 n×m 的矩形网格中有多少对这样的格子满足条件。

输入格式

输入的第一行包含两个正整数 n 和 m,用一个空格分隔。

接下来是 n 行,第 i 行包含 m 个正整数 Ai,1​,Ai,2​,…,Ai,m​,相邻整数之间用一个空格分隔。

输出格式

输出一行包含一个整数表示答案。

输入输出样例

输入 #1复制

3 2 
1 2 
2 3 
3 2

输出 #1复制

6

说明/提示

一共有以下 6 对格子:(1,2)−(2,1),(2,2)−(3,1),(2,1)−(3,2),(2,1)−(1,2),(3,1)−(2,2),(3,2)−(2,1)。

数据范围

对于 20% 的评测用例,1≤n,m≤50;

对于所有评测用例,1≤n,m≤1000,1≤Ai,j​≤1000。

暴力解:

        因为蓝桥杯的赛制与acm不同,通过部分的用例可以获得部分的分数,力求省赛获奖而不求进入国赛的选手(up),对于不会的题可以按照题意直接暴力求解,for循环只管套;例如本题中,需要找到满足|a-c| = |b -d|>0且整数A相等的格子的对数,暴力求解就完全遍历棋盘中的每一个整数,让它与其他的每一个整数运算一遍 ,看两者是否满足条件,满足就累加到ans中。

        

n,m = map(int,input().split())
matrix = []
for i in range(n):
    row = list(map(int,input().split()))
    matrix.append(row)

ans = 0
for i in range(n):
    for j in range(m):
        for ii in range(n):
            for jj in range(m):
                if (matrix[i][j] == matrix[ii][jj] and abs(i-ii) == abs(j-jj) and abs(i-ii) > 0):
                    ans += 1

print(ans)

因为涉及到两对坐标的运算,直接套4层循环,暴力解决,在暴力的同时加上剪枝等操作,就可以通过更多的用例,甚至是全部的用例,不过剪枝需要理解题目,去除不必要的循环,这一点就是题目的难点了,例如:

(b站)

n,m = map(int,input().split())
matrix = []
for i in range(n):
    row = list(map(int,input().split()))
    matrix.append(row)

ans = 0
l = [[0] * (2005) for _ in range(2005)]
r = [[0] * (2005) for _ in range(2005)]

for i in range(n):
    for j in range(m):
        ans += l[matrix[i][j]][i+j]
        ans += r[matrix[i][j]][i-j]
        l[matrix[i][j]][i + j] += 1
        r[matrix[i][j]][i - j] += 1

print(ans*2)

还有别的思路,一个题可能有很多解法:

(解法来自C语言网)

m,n = map(int,input().split())  #m行n列
ans = 0
arr = []
for _ in range(m):
    arr.append([int(i) for i in input().strip().split()])
#两条对角线,每条两个三角区域
#1
for i in range(m):  #(i,j)为这条对角线的起点
    temp = {}  #这一条对角线中每个数字出现的次数
    t = 0
    j = 0
    while 0<=i<m and 0<=j<n:
        if arr[i][j] in temp:
            t += temp[arr[i][j]]  #相当与将这次的数字与之前所有数字配一次对
        else:
            temp[arr[i][j]] = 0
        temp[arr[i][j]] += 1 #if和else两种情况都要执行
        i -= 1
        j += 1
    ans += t
#2
for i in range(m):
    temp = {}
    t = 0
    j = 0
    while 0<=i<m and 0<=j<n:
        if arr[i][j] in temp:
            t += temp[arr[i][j]]
        else:
            temp[arr[i][j]] = 0
        temp[arr[i][j]] += 1
        i += 1
        j += 1
    ans += t
#3
for j in range(1,n):
    temp = {}
    t = 0
    i = m-1
    while 0<=i<m and 0<=j<n:
        if arr[i][j] in temp:
            t += temp[arr[i][j]]
        else:
            temp[arr[i][j]] = 0
        temp[arr[i][j]] += 1
        i -= 1
        j += 1
    ans += t
#4
for j in range(1,n):
    temp = {}
    t = 0
    i = 0
    while 0<=i<m and 0<=j<n:
        if arr[i][j] in temp:
            t += temp[arr[i][j]]
        else:
            temp[arr[i][j]] = 0
        temp[arr[i][j]] += 1
        i += 1
        j += 1
    ans += t
print(ans*2)

### 蓝桥杯 Python 编程竞赛连连看题目解析 #### 题目描述 在一个 n×m 的棋盘上玩连连看游戏。给定一个初始状态的棋盘,其中每个格子可能为空白或者是某种颜色的小球。玩家可以选择两个相同颜色且中间无障碍物阻挡的小球消除它们。如果一次操作可以消去一对小球,则得一分;否则不得分。 目标是在有限步数内获得最高分数并清空整个棋盘。对于任意给出的状态,请计算最多能得多少分以及对应的最优解法路径[^1]。 #### 解题思路 此问题属于图论中的最短路径算法应用之一。可以通过广度优先搜索(BFS)来解决这个问题: - **预处理阶段** - 将输入数据转换成二维列表表示棋盘布局。 - 使用字典记录每种颜色的位置集合以便快速查找匹配项。 - **核心逻辑实现** - 对于每一个未被访问过的节点(即非空白位置),尝试找到与其相连通的所有同色节点形成链表结构。 - 如果该链条长度大于等于2则说明存在可移除组合,此时更新得分并将这些位置标记为已访问。 - 记录下当前状态下所能达到的最大得分及其对应的操作序列直到遍历完整个地图为止。 下面是一个简单的Python代码框架用于求解上述过程: ```python from collections import deque, defaultdict def bfs(board, start_x, start_y): queue = deque([(start_x, start_y)]) visited = set() color_group = [] while queue: x, y = queue.popleft() if (x,y) not in visited and board[x][y]: visited.add((x, y)) color_group.append([x, y]) directions = [(0,-1), (-1,0), (0,+1), (+1,0)] for dx, dy in directions: nx, ny = x + dx, y + dy if 0 <= nx < len(board) and \ 0 <= ny < len(board[0]) and \ board[nx][ny]==board[start_x][start_y]: queue.append((nx, ny)) return color_group if len(color_group)>1 else [] def max_score_of_lianliankan(board): scores = 0 moves = [] colors_positions=defaultdict(list) # Preprocess to record positions of each color. for i in range(len(board)): for j in range(len(board[i])): if board[i][j]!='.': colors_positions[board[i][j]].append((i,j)) for group in colors_positions.values(): for pos in group: matched=bfs(board,*pos) if matched: scores+=len(matched)//2 moves.extend(matched) return scores,moves ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值