题目: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. 绿色优先:先找出所有位置正确且字母正确的方格(绿色)
  2. 黄色受数量限制:绿色匹配过的字母不能再用于黄色匹配
  3. 统计剩余:统计答案中各字母的剩余数量(总数量减去绿色已匹配的数量)
  4. 贪心匹配:遍历猜测中的非绿色位置,如果答案中还有剩余该字母,则标记为黄色

算法步骤

步骤 操作 目的
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:二维布尔数组,标记哪些位置是绿色
  • 遍历每个位置,如果 answerguess 的对应位置字母相同,则为绿色

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. 绿色优先于黄色:必须先处理绿色,再处理黄色
  2. 绿色位置不参与黄色:统计剩余字母时要排除绿色位置
  3. 黄色数量受限:答案中该字母的剩余数量决定了黄色上限
  4. 减少库存:每匹配一个黄色,剩余数量必须减 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)
posted @ 2026-06-27 20:38  kkman2000  阅读(2)  评论(0)    收藏  举报