Herdle

GitHub跳转原题关系图返回列表

先逐格统计绿色,再用每个字母在答案和猜测中的较小频次求总高亮数并扣出黄色。

OJ: usaco

题目 ID: 1179

难度:入门

标签:模拟计数字符串

日期: 2026-07-11 13:19

题意

给定一个正确答案的 3×33 \times 3 字母方阵,以及一次猜测方阵。

如果某个位置的字母完全正确,这个格子标绿色;如果某个字母在答案中出现过,但猜测的位置不正确,这个格子可能标黄色。

要求输出绿色数量和黄色数量。

思路

暴力想法

一个直观做法是:先把所有位置相同的格子标成绿色;再对每个没有变绿的猜测格,找一个还没被使用过、字母相同的答案格,把它标成黄色。

这个做法直接模拟题意:

cpp
/**
 * Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
 * rbook: -> https://rbook.roj.ac.cn  https://rbook2.roj.ac.cn
 * rainboy的学习导航网站: https://idx.roj.ac.cn
 * create_at: 2026-07-11 13:19
 * update_at: 2026-07-11 13:23
 */
// brute.cpp:小数据暴力解,用来帮助理解题意并辅助对拍。
#include <bits/stdc++.h>
using namespace std;

string answer_grid[3];
string guess_grid[3];
bool answer_used[3][3];
bool guess_green[3][3];

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    for (int i = 0; i < 3; i++) {
        cin >> answer_grid[i];
    }
    for (int i = 0; i < 3; i++) {
        cin >> guess_grid[i];
    }

    int green = 0;
    int yellow = 0;

    // 先处理位置完全相同的绿色格子。
    for (int i = 0; i < 3; i++) {
        for (int j = 0; j < 3; j++) {
            if (answer_grid[i][j] == guess_grid[i][j]) {
                green++;
                answer_used[i][j] = true;
                guess_green[i][j] = true;
            }
        }
    }

    // 再给每个没有变绿的猜测格,找一个还没使用过的同字母答案格。
    for (int i = 0; i < 3; i++) {
        for (int j = 0; j < 3; j++) {
            if (guess_green[i][j]) {
                continue;
            }

            bool found = false;
            for (int x = 0; x < 3 && !found; x++) {
                for (int y = 0; y < 3 && !found; y++) {
                    if (!answer_used[x][y] && answer_grid[x][y] == guess_grid[i][j]) {
                        answer_used[x][y] = true;
                        yellow++;
                        found = true;
                    }
                }
            }
        }
    }

    cout << green << '\n';
    cout << yellow << '\n';

    return 0;
}

频次计数

官方解析的关键是把每个字母独立考虑。

对于某个字母 ch,假设它在答案中出现 x 次,在猜测中出现 y 次,那么这个字母最多只能贡献:

min(x,y) \min(x,y)

个高亮格子。这里的高亮包含绿色和黄色。

所以:

text
总高亮数 = 所有字母 min(答案频次, 猜测频次) 的和
黄色数 = 总高亮数 - 绿色数

绿色数只需要逐格比较统计。

代码

cpp
/**
 * Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
 * rbook: -> https://rbook.roj.ac.cn  https://rbook2.roj.ac.cn
 * rainboy的学习导航网站: https://idx.roj.ac.cn
 * create_at: 2026-07-11 13:19
 * update_at: 2026-07-11 13:23
 */
#include <bits/stdc++.h>
using namespace std;

string answer_grid[3];
string guess_grid[3];
int cnt_answer[26];
int cnt_guess[26];

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    for (int i = 0; i < 3; i++) {
        cin >> answer_grid[i];
    }
    for (int i = 0; i < 3; i++) {
        cin >> guess_grid[i];
    }

    int green = 0;

    for (int i = 0; i < 3; i++) {
        for (int j = 0; j < 3; j++) {
            char a = answer_grid[i][j];
            char b = guess_grid[i][j];

            if (a == b) {
                green++;
            }

            cnt_answer[a - 'A']++;
            cnt_guess[b - 'A']++;
        }
    }

    int total_highlight = 0;
    for (int i = 0; i < 26; i++) {
        total_highlight += min(cnt_answer[i], cnt_guess[i]);
    }

    int yellow = total_highlight - green;

    cout << green << '\n';
    cout << yellow << '\n';

    return 0;
}

复杂度

方阵大小固定为 3×33 \times 3,时间复杂度为 O(1)O(1)

使用两个长度为 26 的频次数组,空间复杂度为 O(1)O(1)

总结

这题最容易出错的地方是重复字母。

不要把“猜测里字母存在但位置不同”直接全算成黄色,而要用答案和猜测中该字母出现次数的较小值限制总高亮数量。