算法笔试-编程练习-J-02-23

d这套题,偏向模拟、最后一题可以用BFS或者DP解,整体难度不大。


一、夹吃棋

题目描述

在一个 3 * 3 的棋盘上,小红和小紫正在玩“夹吃棋”。 所谓“夹吃棋”,即如果存在一个白子,它的两侧 (横向或者纵向)相邻都是黑子,则这个棋子将被“夹吃”,对于黑棋亦然。 

如果一个棋盘的局面没有一方被夹吃,或者黑白双方都被对面夹吃,则认为是平局。如果只有一方夹吃了另一方,则认为夹吃方赢,被夹吃方输。 

小红执黑棋,小紫执白棋,现在给定一个局面,请你判断当前棋局是谁获胜。

输入描述

第一行输入一个正整数 t (1 <= t <= 10000),代表询问的次数。 

接下来每组询问输入三行,,每行是一个长度为3的字符串,字符串仅由'o','.','*'组成。

其中 o 代表白棋,* 代表黑棋,. 代表未放置棋子。

输出描述

小红获胜输出“kou”,小紫获胜输出“yukan”,平局输出“draw”。

输入示例
3
...
o*o
...
o**
ooo
..*
o*o
*o*
o*o
输出示例
yukan
kou
draw

题目分析:

【题目类型:纯模拟,遍历,枚举】

夹吃只有横纵两种情况,3*3的棋盘,横有3种,纵有3种,每种情况又分为黑夹白和白夹黑2种。所以一共就12种情况。遍历所有情况,记录黑夹白和白夹黑出现的次数,然后根据题意输出即可。

代码:

def calc(matrix):
    yukan = 0
    kou = 0
    
    # 横向
    for i in range(3):
        if matrix[i][0] == matrix[i][2] and matrix[i][2] == 'o' and matrix[i][1] == '*':
            yukan += 1
        elif matrix[i][0] == matrix[i][2] and matrix[i][2] == '*' and matrix[i][1] == 'o':
            kou += 1
    # 纵向
    for i in range(3):
        if matrix[0][i] == matrix[2][i] and matrix[2][i] == 'o' and matrix[1][i] == '*':
            yukan += 1
        elif matrix[0][i] == matrix[2][i] and matrix[2][i] == '*' and matrix[1][i] == 'o':
            kou += 1
    if (yukan > 0 and kou > 0) or (yukan == 0 and kou == 0):
        return "draw"
    elif yukan > 0:
        return "yukan"
    return "kou"

n = int(input())
for _ in range(n):
    matrix = []
    for i in range(3):
        temp_in = input().split()[0]
        matrix.append([temp_in[0], temp_in[1], temp_in[2]])
    print(calc(matrix))

二、小红买药

题目描述

小红准备买药治病。已知共有 n 种症状和 m 种药,第 i 种药可以治疗一些症状,但可能会导致一些副作用,添加一些新的症状。小红依次服用了一些药,请你告诉小红,当她每次服用一副药时,当前还有多少症状?

输入描述

第一行输入一个正整数 n(1 <= n <= 20),代表症状的数量 

第二行输入一个长应为 n 的 01 串,第 i 位是 "1" 代表小红目前有第 i 个症状,第i位是 "0" 代表没有该症状。 

第三行输入一个正整数 m( 1<= m <= 10^4),代表药的数量。 

接下来的 2 * m 行,每 2 行描述一副药:

第一行输入一个长度为 n 的 01 串,代表该药能治疗的症状。’1‘代表可以治疗,‘0’代表不能治疗。

第二行输入一个长度为 n 的 01 串,代表该药会产生的副作用。’1‘代表会产生该症状,’0‘代表不会产生。 

接下来的一行,输入一个正整数 q( 1<= q <= 10^4),代表小红服用的药数量。 

接下来的 q 行,每行输入一个正整数 u(1 <= ai, u <= m),代表小红服用了第 u 副药。

保证每副药的副作用产生的症状和该药治疗的症状是不会重复的,即不会存在同一个位置的两个 01 串都是‘1’。

输出描述

输出 q 行,每行输入一个正整数,代表当前小红服用药后,身体有多少症状。

输入示例
4
0101
3
1100
0010
0101
1000
1001
0000
3
2
3
1
输出示例
1
0
1

题目分析:

【题目类型:模拟】

没什么算法,理解题意按照描述编写程序即可

代码:

n = int(input())
current_state = [int(i) for i in input()]
m = int(input())
drug_list = []
for _ in range(m):
    drug_list.append([[int(i) for i in input()], [int(i) for i in input()]])

def cure(state, drug):
    for idx in range(len(state)):
        if state[idx] and drug[idx]:
            state[idx] = 0
    return state

def effect(state, drug):
    cnt = 0
    for idx in range(len(state)):
        if drug[idx] == 1 and state[idx] == 0:
            state[idx] = 1
        if state[idx]:
            cnt += 1
    return state, cnt
    
q = int(input())
for _ in range(q):
    idx = int(input()) - 1 
    current_state = cure(current_state, drug_list[idx][0])
    current_state, ans = effect(current_state, drug_list[idx][1])
    print(ans)

三、皇后移动的最小步数

题目描述

有一个 n 行 m 列的棋盘,有一些格子是障碍物不能通过。

小红控制一个皇后在从左上角出发,每次移动她可以控制皇后进行以下三种方式中的一种:

1.向右移动若干个格子。

2.向下移动若干个格子。

3.向右下移动若干个格子。

用数学语言描述,当前的坐标在 (x, y) 时,每次移动可以到 (x + k, y) 或 (x, y + k) 或 (x + k, y + k) 其中 k 为任意正整数。移动的前提是,路径上没有障碍物。 小红想知道,皇后从左上角移动到右下角,最少要移动多少步?

输入描述

第一行输入两个正整数 n 和 m(1 <= n,m <= 2000),代表行数和列数。 

接下来的 n 行,每行输入一个长度 m 的字符串,用来表示棋盘。

其中 "." 代表可以通过的位置,"*" 代表障碍物。 保证左上角和右下角都不是障碍物。

输出描述

如果无法到达,请输出-1。 

否则输出一个整数,代表最少的移动次数。

输入示例
4 5
...*.
*..**
.....
.....
输出示例
2

题目分析:

【题目类型:动态规划、BFS】

动态规划的思想,是用dp[i][j][w]保存最后一步用方式w,到达i, j的最小步数,后面的位置可以根据前面的位置的步数求得。

BFS的思想,是从1,1点出发,第n次BFS到达终点处,那么就是最少的步数。

同样的思想,其他语言的代码可以跑通。但是python最后几个n和m为2000用例总是跑不过,不太清楚是为什么,可能是python的问题。

代码:

# BFS
n, m = map(int, input().split())
grid = [input() for _ in range(n)] # 输入地图的每一行

visited = [[ False for _ in range(m)] for __ in range(n)]
ways = [[1, 0], [0, 1], [1, 1]]


def bfs(grid, n, m):
    if grid[n-1][m-1] == "*":
        return -1
    
    if n == 1 and m == 1:
        return 0

    queue = [[0,0]]
    visited[0][0] = True
    step = 0
    while len(queue) > 0:   
        step += 1
        next_queue = []
        for xy in queue:
            for w in ways:
                next_x = xy[0] + w[0]
                next_y = xy[1] + w[1]
                while next_x < n and next_y < m and grid[next_x][next_y] == ".":
                    if not visited[next_x][next_y]:
                        if next_x == n-1 and next_y == m-1:
                            return step
                        visited[next_x][next_y] = True
                        next_queue.append([next_x, next_y])
                    next_x += w[0]
                    next_y += w[1]
        queue = next_queue
    return -1

print(bfs(grid, n, m))
# 动态规划
n, m = map(int, input().split())
grid = [list(input()) for _ in range(n)] # 输入地图的每一行

dp = [[[10000000, 10000000, 10000000] for _ in range(m)] for __ in range(n)]    # n*m <= 4000000, [-1, -1, -1] 分别表示按照向右、向下、向右下的方式来到的步数      
dp[0][0] = [1, 1, 1]
for i in range(n):
    for j in range(m):
        if grid[i][j] == "*" or i+j == 0:
            continue
        dp[i][j][0] = min(dp[i][j-1][0], min(dp[i][j-1])+1)
        dp[i][j][1] = min(dp[i-1][j][1], min(dp[i-1][j])+1)
        dp[i][j][2] = min(dp[i-1][j-1][2], min(dp[i-1][j-1])+1)
 
ans = min(dp[n-1][m-1])
if ans >= 10000000:
    ans = -1
print(ans)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值