题目:Herdle(USACO 2022 年 1 月铜组)
import sys
# ==================== 读取输入 ====================
# 读取正确答案的 3x3 方阵
answer = []
for _ in range(3):
line = sys.stdin.readline().strip()
answer.append(line)
# 读取猜测的 3x3 方阵
guess = []
for _ in range(3):
line = sys.stdin.readline().strip()
guess.append(line)
# ==================== 统计绿色 ====================
green = 0
green_pos = [[False] * 3 for _ in range(3)]
for row in range(3):
for col in range(3):
if answer[row][col] == guess[row][col]:
green += 1
green_pos[row][col] = True
# ==================== 统计答案中剩余字母 ====================
# 只统计非绿色位置的字母(绿色位置已匹配,不再参与黄色判断)
ans_count = {}
for row in range(3):
for col in range(3):
if not green_pos[row][col]:
letter = answer[row][col]
ans_count[letter] = ans_count.get(letter, 0) + 1
# ==================== 统计黄色 ====================
yellow = 0
for row in range(3):
for col in range(3):
if not green_pos[row][col]:
letter = guess[row][col]
# 检查该字母在答案中是否还有剩余数量
if ans_count.get(letter, 0) > 0:
yellow += 1
ans_count[letter] = ans_count.get(letter, 0) - 1
# ==================== 输出结果 ====================
print(green)
print(yellow)
题目:Herdle(USACO 2022 年 1 月铜组)
题目描述
奶牛们发明了一种名为 Herdle 的新型解谜游戏。每天都会有一个新谜题发布供奶牛解决。游戏采用 3×3 方阵的形式表示农场的一块田地,田地的每个方格都由特定品种的奶牛占据。总共只有 26 种可能的品种,每一种由 A 到 Z 中的不同大写字母标识。
玩家不会被告知田地中的奶牛品种排列方式——游戏目标是通过一系列猜测确定它们。
每次猜测,奶牛们输入一个 3×3 的大写字母方阵,表示该田地可以用奶牛填充的可能方式。猜测的某些方格可能是正确的。这些方格以绿色高亮显示,让奶牛们知道这些是正确的。
猜测的另一些方格可能填入了品种正确但位置错误的奶牛。这些以黄色高亮显示。
黄色高亮显示的方格的数量可以帮助指示某个品种的奶牛数量。 例如,假设猜测方阵包含 4 头品种 A 的奶牛,而答案方阵包含 2 只品种 A 的奶牛,其中没有正确位置上的 A(即,它们都不应该是绿色的)。在这种情况下,猜测方阵中只有两个 A 应以黄色高亮显示。
更准确地说,如果猜测方阵中有 x 个特定品种的奶牛,并且答案方阵中有 y ≤ x 头该品种奶牛(不包括位置正确而得到绿色高亮显示的奶牛),那么猜测方阵的 x 头奶牛中只有 y 头奶牛应该以黄色高亮显示。
给定正确答案的方阵和一个表示对该答案的猜测的方阵,请计算绿色和黄色高亮显示的方格的数量。
输入格式
输入的前 3 行给定了正确答案的方阵。以下 3 行表示对该答案的猜测。
输出格式
输出两行。输出的第一行包含应当以绿色高亮显示的方格的数量。输出的第二行包含应当以黄色高亮显示的方格的数量。
输入输出样例
输入 #1
COW
SAY
MOO
WIN
THE
IOI
输出 #1
1
1
样例解释 1:在这个例子中,最后一行中间的 O 是正确的,所以这个方格以绿色高亮显示。字母 W 位于错误的位置,所以它以黄色高亮显示。
输入 #2
AAA
BBB
CCC
AYY
AAA
ZZZ
输出 #2
1
2
样例解释 2:在这里,其中一个 A 位于正确的位置,所以它以绿色高亮显示。余下的 A 均不在正确位置上,由于答案方阵中有两个 A,所以有两个 A 应当以黄色高亮显示。
解题思路
核心要点
- 绿色优先:先找出所有位置正确且字母正确的方格(绿色)
- 黄色受数量限制:绿色匹配过的字母不能再用于黄色匹配
- 统计剩余:统计答案中各字母的剩余数量(总数量减去绿色已匹配的数量)
- 贪心匹配:遍历猜测中的非绿色位置,如果答案中还有剩余该字母,则标记为黄色
算法步骤
| 步骤 | 操作 | 目的 |
|---|---|---|
| 1 | 遍历 3×3 方阵,对比相同位置 | 找出绿色匹配 |
| 2 | 标记绿色位置 | 排除这些位置不参与黄色判断 |
| 3 | 统计答案中各字母剩余数量 | 建立可用字母库存 |
| 4 | 遍历猜测中的非绿色位置 | 尝试匹配黄色 |
| 5 | 检查答案中是否还有剩余该字母 | 决定是否可标记为黄色 |
| 6 | 黄色匹配后减少库存 | 确保数量限制 |
为什么不能用简单计数?
假设答案有 A:2,猜测有 A:3(位置都不对):
- 如果简单统计,可能会认为 3 个都是黄色
- 但答案只有 2 个 A,所以最多只能有 2 个黄色
- 因此需要维护一个"剩余数量"的计数器,匹配一个就减少一个
代码详解
1. 读取输入
answer = []
for _ in range(3):
line = sys.stdin.readline().strip()
answer.append(line)
guess = []
for _ in range(3):
line = sys.stdin.readline().strip()
guess.append(line)
逐行读取 3×3 方阵,存入列表。strip() 去除末尾换行符。
2. 统计绿色
green = 0
green_pos = [[False] * 3 for _ in range(3)]
for row in range(3):
for col in range(3):
if answer[row][col] == guess[row][col]:
green += 1
green_pos[row][col] = True
green:绿色方格计数green_pos:二维布尔数组,标记哪些位置是绿色- 遍历每个位置,如果
answer和guess的对应位置字母相同,则为绿色
3. 统计答案中剩余字母
ans_count = {}
for row in range(3):
for col in range(3):
if not green_pos[row][col]: # 只统计非绿色位置
letter = answer[row][col]
ans_count[letter] = ans_count.get(letter, 0) + 1
- 使用字典
ans_count统计答案中各字母的出现次数 - 关键:只统计非绿色位置!绿色位置已经匹配,不能再参与黄色匹配
dict.get(letter, 0):如果字母不存在,返回 0,避免 KeyError
示例:答案 AAA/BBB/CCC,猜测 AYY/AAA/ZZZ
- 绿色:(1,0) 位置的 A(第二行第一列)
- 剩余答案:
A:2, B:3, C:3(第一行两个 A,加上 BBB 和 CCC)
4. 统计黄色
yellow = 0
for row in range(3):
for col in range(3):
if not green_pos[row][col]: # 只处理非绿色位置
letter = guess[row][col]
if ans_count.get(letter, 0) > 0: # 答案中还有剩余
yellow += 1
ans_count[letter] = ans_count.get(letter, 0) - 1
- 遍历猜测中的非绿色位置
- 检查该字母在答案中是否还有剩余(
ans_count.get(letter, 0) > 0) - 如果有,标记为黄色,并减少剩余数量
接上例:猜测 AYY/AAA/ZZZ
- 非绿色位置:(0,0)=A, (0,1)=Y, (0,2)=Y, (1,1)=A, (1,2)=A, (2,0)=Z, (2,1)=Z, (2,2)=Z
- (0,0)=A:答案剩余 A=2 > 0,黄色+1,A 剩余变为 1
- (0,1)=Y:答案剩余 Y=0,不是黄色
- (1,1)=A:答案剩余 A=1 > 0,黄色+1,A 剩余变为 0
- (1,2)=A:答案剩余 A=0,不是黄色
- 其他 Z 同理不匹配
最终:黄色 = 2
5. 输出结果
print(green)
print(yellow)
按题目要求输出两行。
复杂度分析
| 项目 | 复杂度 | 说明 |
|---|---|---|
| 时间 | O(9) = O(1) | 固定 3×3 = 9 个格子 |
| 空间 | O(26) = O(1) | 最多 26 个不同字母 |
关键易错点
- 绿色优先于黄色:必须先处理绿色,再处理黄色
- 绿色位置不参与黄色:统计剩余字母时要排除绿色位置
- 黄色数量受限:答案中该字母的剩余数量决定了黄色上限
- 减少库存:每匹配一个黄色,剩余数量必须减 1
完整代码(最终版本)
import sys
# ==================== 读取输入 ====================
# 读取正确答案的 3x3 方阵
answer = []
for _ in range(3):
line = sys.stdin.readline().strip()
answer.append(line)
# 读取猜测的 3x3 方阵
guess = []
for _ in range(3):
line = sys.stdin.readline().strip()
guess.append(line)
# ==================== 统计绿色 ====================
green = 0
green_pos = [[False] * 3 for _ in range(3)]
for row in range(3):
for col in range(3):
if answer[row][col] == guess[row][col]:
green += 1
green_pos[row][col] = True
# ==================== 统计答案中剩余字母 ====================
# 只统计非绿色位置的字母(绿色位置已匹配,不再参与黄色判断)
ans_count = {}
for row in range(3):
for col in range(3):
if not green_pos[row][col]:
letter = answer[row][col]
ans_count[letter] = ans_count.get(letter, 0) + 1
# ==================== 统计黄色 ====================
yellow = 0
for row in range(3):
for col in range(3):
if not green_pos[row][col]:
letter = guess[row][col]
# 检查该字母在答案中是否还有剩余数量
if ans_count.get(letter, 0) > 0:
yellow += 1
ans_count[letter] = ans_count.get(letter, 0) - 1
# ==================== 输出结果 ====================
print(green)
print(yellow)

浙公网安备 33010602011771号