题一
难度:普及-
https://www.luogu.com.cn/problem/P1331
题目背景
在峰会期间,武装部队得处于高度戒备。警察将监视每一条大街,军队将保卫建筑物,领空将布满了 F-2003 飞机。
此外,巡洋船只和舰队将被派去保护海岸线。不幸的是,因为种种原因,国防海军部仅有很少的几位军官能指挥大型海战。因此,他们培养了一些新海军指挥官。军官们选择了“海战”游戏来帮助他们学习。
题目描述
在一个方形的盘上,放置了固定数量和形状的船只,每只船却不能碰到其它的船。在本题中,我们认为船是方形的,所有的船只都是由图形组成的方形。
求出该棋盘上放置的船只的总数。
输入格式
第一行为两个整数 R 和 C,用空格隔开,分别表示游戏棋盘的行数和列数。
接下来 R 行,每行 C 个字符,为 # 或 .。# 表示船只的一部分,. 表示水。
输出格式
一行一个字符串,如果船的位置放得正确(即棋盘上只存在相互之间不能接触的方形,如果两个 # 号上下相邻或左右相邻却分属两艘不同的船只,则称这两艘船相互接触了)。就输出 There are S ships.,S 表示船只的数量。否则输出 Bad placement.。
输入输出样例 #1
输入 #1
1 2 3 4 5 6 7
| 6 8 .....#.# ##.....# ##.....# .......# #......# #..#...#
|
输出 #1
说明/提示
对于 100% 的数据,1≤R,C≤1000。
解题思路
不同于常规的单次对全部数据bfs,这题需要对所有相互不连通的#区域单独bfs
定义bfs函数并返回一个布尔值,该布尔值表示这段连通的#是否是一搜合法的船
如何高效的判断一段连通的#是否为一个标准的矩形呢,一次简单的计算即可:
完整代码实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| import sys from collections import deque from array import array
r, c = map(int, input().split()) grid = [] for _ in range(r): row = list(sys.stdin.readline().strip()) grid.append(row) visited = [[False] * c for _ in range(r)] dire = [(0, 1), (0, -1), (1, 0), (-1, 0)] count = 0
def bfs(begin): q = deque() visx = array("i", []) visy = array("i", []) cnt = 1 q.append(begin) while q: x, y = q.popleft() visx.append(x) visy.append(y) visited[x][y] = True for dx, dy in dire: if 0 <= x + dx < r and 0 <= y + dy < c and not visited[x + dx][y + dy] and grid[x+dx][y+dy] == '#': q.append((x + dx, y + dy)) visited[x + dx][y + dy] = True visx.append(x + dx) visy.append(y + dy) cnt += 1 return cnt == (max(visx) - min(visx) + 1) * (max(visy) - min(visy) + 1)
for i in range(r): for j in range(c): if grid[i][j] == '#' and not visited[i][j]: if not bfs((i, j)): print("Bad placement.") sys.exit() count += 1 print(f"There are {count} ships.")
|
题二
难度:普及/提高-
https://www.luogu.com.cn/problem/P1135
题目描述
呵呵,有一天我做了一个梦,梦见了一种很奇怪的电梯。大楼的每一层楼都可以停电梯,而且第 i 层楼(1≤i≤N)上有一个数字 Ki(0≤Ki≤N)。电梯只有四个按钮:开,关,上,下。上下的层数等于当前楼层上的那个数字。当然,如果不能满足要求,相应的按钮就会失灵。例如:3,3,1,2,5 代表了 Ki(K1=3,K2=3,……),从 1 楼开始。在 1 楼,按“上”可以到 4 楼,按“下”是不起作用的,因为没有 −2 楼。那么,从 A 楼到 B 楼至少要按几次按钮呢?
输入格式
共二行。
第一行为三个用空格隔开的正整数,表示 N,A,B(1≤N≤200,1≤A,B≤N)。
第二行为 N 个用空格隔开的非负整数,表示 Ki。
输出格式
一行,即最少按键次数,若无法到达,则输出 -1。
输入输出样例 #1
输入 #1
输出 #1
说明/提示
对于 100% 的数据,1≤N≤200,1≤A,B≤N,0≤Ki≤N。
本题共 16 个测试点,前 15 个每个测试点 6 分,最后一个测试点 10 分。
解题思路
这题也是比较简单,常规搜法,2个方向,加一个越界判断即可
完整代码实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| from collections import deque import sys
n,a,b = map(int,sys.stdin.readline().strip().split()) data = list(map(int,sys.stdin.readline().strip().split())) q = deque([(a,0)]) visited = [False]*(n+1) visited[a] = True dires = [1,-1] if a == b: print(0) sys.exit() while q: pos,step = q.popleft() for dir in dires: if 1 <= pos + data[pos-1]*dir <= n and pos + data[pos-1]*dir != b and not visited[pos + data[pos-1]*dir]: visited[pos + data[pos-1]*dir] = True q.append((pos + data[pos-1]*dir,step+1)) elif pos + data[pos-1]*dir == b: print(step+1) sys.exit() print(-1)
|
题三
难度:普及+/提高
https://www.luogu.com.cn/problem/P1126
题目描述
机器人移动学会(RMI)现在正尝试用机器人搬运物品。机器人的形状是一个直径 1.6 米的球。在试验阶段,机器人被用于在一个储藏室中搬运货物。储藏室是一个 N×M 的网格,有些格子为不可移动的障碍。机器人的中心总是在格点上,当然,机器人必须在最短的时间内把物品搬运到指定的地方。机器人接受的指令有:
- 向前移动 1 步(
Creep);
- 向前移动 2 步(
Walk);
- 向前移动 3 步(
Run);
- 向左转(
Left);
- 向右转(
Right)。
每个指令所需要的时间为 1 秒。请你计算一下机器人完成任务所需的最少时间。
输入格式
第一行为两个正整数 N,M (1≤N,M≤50),下面 N 行是储藏室的构造,0 表示无障碍,1 表示有障碍,数字之间用一个空格隔开。接着一行有 4 个整数和 1 个大写字母,分别为起始点和目标点左上角网格的行与列,起始时的面对方向(东 E,南 S,西 W,北 N),数与数,数与字母之间均用一个空格隔开。终点的面向方向是任意的。
输出格式
一个整数,表示机器人完成任务所需的最少时间。如果无法到达,输出 −1。

输入输出样例 #1
输入 #1
1 2 3 4 5 6 7 8 9 10 11
| 9 10 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 7 2 2 7 S
|
输出 #1
解题思路
这题有一些坑点:
- 障碍物在方格内,而机器人是行走在网格线上的,这意味着一个方格的障碍物会导致方格的4个定点都不可到达
- 机器人是直径1.6的圆形,这意味着机器人的实际占用空间是4个方格
技巧:
- 预处理
valid数组,记录所有机器人可以走的格点坐标(排除网格边界和障碍)
- 方向整数化:机器人面朝方向以字符串输入,不易操作,可将其转化为0~3的整数
- visited需要设定为三维数组,不仅记录机器人的位置坐标,还要记录其面朝方向
- 队列中记录4个信息:坐标x,y,面朝方向,当前步数
完整代码实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81
| import sys from collections import deque
n, m = map(int, sys.stdin.readline().strip().split()) visited = [[False] * m for _ in range(n)] grid = [] for _ in range(n): row = list(map(int, sys.stdin.readline().strip().split())) grid.append(row) bx, by, ex, ey, dir = sys.stdin.readline().strip().split() if dir == 'S': dir = 0 elif dir == 'W': dir = 1 elif dir == 'N': dir = 2 elif dir == 'E': dir = 3 bx, by, ex, ey = map(int, (bx, by, ex, ey))
valid = [[True] * (m + 1) for _ in range(n + 1)] for i in range(n): for j in range(m): if grid[i][j] == 1: valid[i][j] = False valid[i + 1][j] = False valid[i][j + 1] = False valid[i + 1][j + 1] = False for i in range(n + 1): valid[i][0] = valid[i][m] = False for i in range(m + 1): valid[0][i] = valid[n][i] = False
q = deque([(bx, by, dir, 0)]) visited = [[[False] * 4 for _ in range(m + 1)] for _ in range(n + 1)] visited[bx][by][dir] = True
while q: x, y, direc, step = q.popleft() if x == ex and y == ey: print(step) sys.exit()
for ste in range(1, 4): if direc == 0: if 0 <= x + ste <= n and valid[x + ste][y]: if not visited[x + ste][y][direc]: q.append((x + ste, y, direc, step + 1)) visited[x + ste][y][direc] = True else: break elif direc == 2: if 0 <= x - ste <= n and valid[x - ste][y]: if not visited[x - ste][y][direc]: q.append((x - ste, y, direc, step + 1)) visited[x - ste][y][direc] = True else: break elif direc == 1: if 0 <= y - ste <= m and valid[x][y - ste]: if not visited[x][y - ste][direc]: q.append((x, y - ste, direc, step + 1)) visited[x][y - ste][direc] = True else: break elif direc == 3: if 0 <= y + ste <= m and valid[x][y + ste]: if not visited[x][y + ste][direc]: q.append((x, y + ste, direc, step + 1)) visited[x][y + ste][direc] = True else: break
if not visited[x][y][(direc + 1) % 4]: q.append((x, y, (direc + 1) % 4, step + 1)) visited[x][y][(direc + 1) % 4] = True if not visited[x][y][(direc - 1) % 4]: q.append((x, y, (direc - 1) % 4, step + 1)) visited[x][y][(direc - 1) % 4] = True
print(-1)
|
不得不承认很高的重复度证明这是一坨屎山代码,但我认为这么写是容易理解的
题四
难度:普及+/提高
https://www.luogu.com.cn/problem/P1144
题目描述
给出一个 N 个顶点 M 条边的无向无权图,顶点编号为 1∼N。问从顶点 1 开始,到其他每个点的最短路有几条。
输入格式
第一行包含 2 个正整数 N,M,为图的顶点数与边数。
接下来 M 行,每行 2 个正整数 x,y,表示有一条连接顶点 x 和顶点 y 的边,请注意可能有自环与重边。
输出格式
共 N 行,每行一个非负整数,第 i 行输出从顶点 1 到顶点 i 有多少条不同的最短路,由于答案有可能会很大,你只需要输出 ansmod100003 后的结果即可。如果无法到达顶点 i 则输出 0。
输入输出样例 #1
输入 #1
1 2 3 4 5 6 7 8 9
| 5 7 1 2 1 3 2 4 3 4 2 3 4 5 4 5
|
输出 #1
说明/提示
1 到 5 的最短路有 4 条,分别为 2 条 1→2→4→5 和 2 条 1→3→4→5(由于 4→5 的边有 2 条)。
对于 20% 的数据,1≤N≤100;
对于 60% 的数据,1≤N≤103;
对于 100% 的数据,1≤N≤106,1≤M≤2×106。
解题思路
技巧:
- 用代码表示节点到节点的连通:建立二维数组,每个子数组表示一个节点,子数组中存储的数字表示能与其连通的节点
dist数组存储节点1到某一节点最短路径的长度,初始化为INF,dist[1] = 0
ans数组存储最短路径的条数,初始化为0,ans[1] = 1
完整代码实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| import sys from collections import deque
data = sys.stdin.read().strip().split() idx = 0 n = int(data[idx]) idx += 1 m = int(data[idx]) idx += 1 graph = [[] for _ in range(n+1)] INF = float("inf") for _ in range(m): x = int(data[idx]) idx += 1 y = int(data[idx]) idx += 1 graph[x].append(y) graph[y].append(x)
dist = [INF]*(n+1) dist[1] = 0 ans = [0]*(n+1) ans[1] = 1 q = deque() q.append(1) while q: now = q.popleft() for i in graph[now]: if dist[i] == dist[now]+1: ans[i] = (ans[i] + ans[now]) % 100003 elif dist[i] > dist[now]+1: dist[i] = dist[now]+1 ans[i] = ans[now] q.append(i) output = [str(ans[i]) for i in range(1, n+1)] sys.stdout.write('\n'.join(output))
|
由于Python语言自身的局限性,面对这题的极端大数据时绝对会TLE,在洛谷提交时把语言改成PyPy3即可
晚上开始DFS喵~