课堂计划
P3416 [USACO16DEC] Moocast S
https://usaco.org/index.php?page=viewproblem2&cpid=668
约翰农场主的 $N$ 头奶牛需要建立一个广播系统,每头奶牛有一个对讲机,具有一定的传输半径 $P$。一头奶牛可以通过直接或中继的方式,将信息传递给其他奶牛。目标是找到从某头奶牛开始广播时,能够到达的奶牛的最大数量。
算法分析
- 图的构建:
- 每头奶牛看作一个节点。
-
如果奶牛 $i$ 的对讲机能直接覆盖奶牛 $j$,则在图中从 $i$ 到 $j$ 添加一条有向边。
-
广度优先搜索 (BFS):
- 从每个节点开始,使用 BFS 遍历可达的所有节点。
- 记录从某个节点开始可以到达的最大节点数。
代码注释
# 读取奶牛数量
n = int(input())
# 初始化邻接表,用于存储每头奶牛可以直接发送信息到达的奶牛
e = [[] for _ in range(n)]
# 初始化位置和能量列表
pos, p = [], []
# 读取每头奶牛的位置和能量
for _ in range(n):
x1, y1, p1 = map(int, input().split())
pos.append((x1, y1))
p.append(p1)
# 计算两头奶牛之间的距离平方
def dis(a, b):
return (a[0] - b[0]) ** 2 + (a[1] - b[1]) ** 2
# 构建图,确定每头奶牛可以直接向哪些奶牛发送信息
for i in range(n):
for j in range(n):
if i == j: continue # 跳过自己
# 如果奶牛 j 在奶牛 i 的传输范围内,则添加到邻接表
if dis(pos[i], pos[j]) <= p[i] ** 2:
e[i].append(j)
from collections import deque
# 初始化最大可到达奶牛数量
ans = 0
# 对每头奶牛执行广度优先搜索(BFS)
for i in range(n):
# 用于记录访问过的奶牛
vis = [False] * n
# 创建队列进行 BFS
q = deque()
q.append(i)
tot = 0
vis[i] = True
while len(q) > 0:
tot += 1
u = q.popleft()
# 遍历当前奶牛可以直接到达的奶牛
for v in e[u]:
if not vis[v]: # 如果奶牛 v 未访问过
q.append(v)
vis[v] = True
# 更新最大可到达奶牛数量
if tot > ans:
ans = tot
# 输出最大可到达奶牛数量
print(ans)
程序填空版
n = int(input())
e = [[] for _ in range(n)]
pos, p = [], []
for _ in range(n):
x1, y1, p1 = map(int, input().split())
pos.append((x1, y1))
p.append(p1)
def dis(a, b):
# 计算两头奶牛之间的距离平方
return (a[0] - b[0]) ** 2 + (a[1] - b[1]) ** 2
for i in range(n):
for j in range(n):
if i == j: continue
# 如果奶牛 j 在奶牛 i 的传输范围内,则添加到邻接表
if dis(pos[i], pos[j]) <= ________:
e[i].append(j)
from collections import ________
ans = 0
for i in range(n):
# 用于记录访问过的奶牛
vis = [False] * n
# 创建队列进行 BFS
q = deque()
q.append(i)
tot = 0
vis[i] = ________
while len(q) > 0:
tot += 1
u = q.________()
# 遍历当前奶牛可以直接到达的奶牛
for v in e[u]:
if not vis[v]:
q.append(v)
vis[v] = ________
# 更新最大可到达奶牛数量
if tot > ans:
ans = tot
# 输出最大可到达奶牛数量
print(______)
该算法使用图的表示和 BFS 来计算每头奶牛作为起点时,最多可以到达多少头奶牛。通过遍历每个节点并执行 BFS,我们可以找到最大的可达节点数。复杂度主要受 BFS 和图的构建影响,为 $O(N^2)$。
P6111 [USACO18JAN] MooTube S
https://usaco.org/index.php?page=viewproblem2&cpid=788
树的性质:
由于是树形结构,任意两个节点之间有且仅有一条路径。 任意两个视频间的相关性是路径上所有边中相关性最小的那一条。 解题思路 深度优先搜索 (DFS): 我们可以从给定的视频节点出发,使用 DFS 遍历整棵树。 在遍历过程中,只访问那些与当前节点相关性大于等于 K 的节点。 计数满足条件的节点。
def dfs(u, fa, k):
global cnt
# 遍历当前节点 u 的所有邻接节点
for v, w in G[u]:
# 如果该节点不是父节点且相关性 w 大于等于 k
if v != fa and w >= k:
cnt += 1 # 满足条件的节点计数加一
dfs(v, u, k) # 递归调用 DFS
import sys
# 增加递归深度限制,确保 DFS 不会因深度过大而失败
sys.setrecursionlimit(10000)
n, Q = map(int, input().split())
G = [[] for _ in range(n + 1)] # 初始化邻接表
# 读取 N-1 条边的信息
for _ in range(n - 1):
p, q, r = map(int, input().split())
G[p].append((q, r)) # 添加边 p -> q
G[q].append((p, r)) # 添加边 q -> p (无向图)
# 处理每个查询
for _ in range(Q):
k, v = map(int, input().split())
cnt = 0 # 初始化计数
dfs(v, -1, k) # 从节点 v 开始 DFS,父节点设为 -1 表示无父节点
print(cnt) # 输出满足条件的视频数量
填空:
def dfs(u, fa, k):
global cnt
# 遍历当前节点 u 的所有邻接节点
for v, w in G[u]:
# 如果该节点不是父节点且相关性 w 大于等于 k
if ___ and ___:
cnt += 1 # 满足条件的节点计数加一
dfs(___) # 递归调用 DFS
import sys
# 增加递归深度限制,确保 DFS 不会因深度过大而失败
sys.setrecursionlimit(10000)
n, Q = map(int, input().split())
G = [[] for _ in range(___)] # 初始化邻接表
# 读取 N-1 条边的信息
for _ in range(n - 1):
p, q, r = map(int, input().split())
G[p].append((q, r)) # 添加边 p -> q
G[q].append((___, ___)) # 添加边 q -> p (无向图)
# 处理每个查询
for _ in range(Q):
k, v = map(int, input().split())
cnt = ___ # 初始化计数
dfs(v, ___, k) # 从节点 v 开始 DFS,父节点设为 -1 表示无父节点
print(___) # 输出满足条件的视频数量
作业题 # P2997 [USACO10NOV] Banner S
https://www.luogu.com.cn/problem/P2997
平面上有(0,0)到(n,m)的(n+1)*(m+1)个点。问有多少点对所连的线段不过其他点,且长度在[l,h]范围内
枚举 dx, dy, dx 与 dy 互质即可。