小蓝得到了一副大小为 M × N 的格子地图,可以将其视作一个只包含字符‘0’(代表海水)和 ‘1’(代表陆地)的二维数组,地图之外可以视作全部是海水,每个岛屿由在上/下/左/右四个方向上相邻的 ‘1’ 相连接而形成。
在岛屿 A 所占据的格子中,如果可以从中选出 k 个不同的格子,使得他们的坐标能够组成一个这样的排列:(x0,y0),(x1,y1),...,(xk−1,yk−1),其中(x(i+1)%k,y(i+1)%k)是由(xi,yi) 通过上/下/左/右移动一次得来的 (0 ≤ i ≤ k − 1),
此时这 k 个格子就构成了一个 “环”。如果另一个岛屿 B 所占据的格子全部位于这个 “环” 内部,此时我们将岛屿 B 视作是岛屿 A 的子岛屿。若 B 是 A 的子岛屿,C 又是 B 的子岛屿,那 C 也是 A 的子岛屿。
请问这个地图上共有多少个岛屿?在进行统计时不需要统计子岛屿的数目。
next_p = [(0,1),(1,0),(0,-1),(-1,0)] next_q = [(1,0),(0,1),(-1,0),(0,-1),(1,1),(1,-1),(-1,1),(-1,-1)] defsearch_island(x,y): global sea_map global visited # BFS q = [] q.append((x,y)) while q: x1,y1 = q[0][0], q[0][1] q.pop(0) if visited[x1][y1]: continue # only search the island visited[x1][y1] = 1 for d in next_p: if sea_map[x1+d[0]][y1+d[1]] == '1'and visited[x1+d[0]][y1+d[1]] == False: q.append((x1+d[0], y1+d[1]))
t = int(input()) sea_map = [] visited = [] for i inrange(t): # initialize sea_map = [] visited = [] m,n = map(int, input().split()) sea_map.append('0'*(n+2)) for j inrange(m): sea_map.append('0' + input() + '0') sea_map.append('0'*(n+2)) visited = [[0]*(n+2) for k inrange(m+2)] # bfs ans = 0 q = [] q.append((0,0)) while q: x, y = q[0][0], q[0][1] q.pop(0) if visited[x][y]: continue # begin to visit this node if sea_map[x][y] == '0': # sea visited[x][y] = 1 # push the nodes that near it into the queue for d in next_q: if0 <= x+d[0] <= m+1and0 <= y+d[1] <= n+1and visited[x+d[0]][y+d[1]] == False: q.append((x+d[0], y+d[1])) else: # island ans += 1 search_island(x,y) print(ans) for line in visited: print(line)
例题 2:最少的1(蓝桥杯第13届国赛)
题目描述:
给定1个正整数n,找出所有n的倍数中,用二进制表示法表示下1的个数最少是多少?
输入格式:
输入一行包含一个整数n
输出格式:
输出一行包含一个整数表示答案
解题思路:
二进制数的特殊进位方式 + 同余最短路径 我们希望找到一个 n 的倍数,它的二进制只包含 0 和 1。问题转换为要从只由 1 和 0 构成的二进制数中,挑选一个最小的 n 的倍数。也就是将所有只包含 0 和 1 的十进制数(例如 1,10,11,100,101,…)按构造顺序尝试,直到找到一个是 n 的倍数为止。但因为这些数太多,不能直接枚举数值,而是使用BFS + 模 n 的余数来避免爆炸。