1 条题解

  • 0
    @ 2026-10-27 4:21:40

    思路与算法

    枚举唯一罪犯和星期。对每个识别到的证词求真假;同一说话者的全部有效证词必须全真或全假,有矛盾则该假设不成立。统计被迫说谎人数L,以及没有任何有效证词的人数U,恰好N人说谎可行当且仅当L≤N≤L+U。收集能在任意星期成立的罪犯,按0、1、多个分别输出Impossible、名字、Cannot Determine。

    正确性说明

    罪犯和星期给定后,每条规定格式证词的真值唯一确定。真话者不能说假证词、说谎者不能说真证词,所以一个人证词真假混杂必不可能;一致时身份被唯一确定。没有有效证词者可以任选身份,只需从U人中选N-L个说谎者,区间条件正好充要。枚举全部罪犯与七天穷尽所有世界,收集结果就准确表达唯一性。

    复杂度

    O(7MPL+7M²)时间、O(M+PL)空间,L≤250为证词长度;包含姓名字典、证词解析和每个假设的身份数组初始化。

    易错点

    非规定格式的话必须忽略,不能当作假话。罪犯不一定说谎;一天未知但所有人的星期证词指同一天。原样例全角句号按普通句号识别,冒号后有无空格都能读入。证词表图片已核对并随题包保留。

    参考代码(C++11)

    #include <bits/stdc++.h>
    using namespace std;
    struct Statement {
        int who, type, arg;
    };
    int main() {
        ios::sync_with_stdio(false);
        cin.tie(nullptr);
        int M, N, P;
        cin >> M >> N >> P;
        vector<string> names(M);
        map<string, int> id;
        for (int i = 0; i < M; i++) {
            cin >> names[i];
            id[names[i]] = i;
        }
        vector<string> days = {"Monday", "Tuesday",  "Wednesday", "Thursday",
                               "Friday", "Saturday", "Sunday"};
        string line;
        getline(cin, line);
        vector<Statement> st;
        for (int i = 0; i < P; i++) {
            getline(cin, line);
            string full = ".";
            size_t pos;
            while ((pos = line.find(full)) != string::npos)
                line.replace(pos, full.size(), ".");
            auto colon = line.find(':');
            string who = line.substr(0, colon), text = line.substr(colon + 1);
            while (!text.empty() && text.front() == ' ')
                text.erase(text.begin());
            if (text == "I am guilty.")
                st.push_back({id.at(who), 0, id.at(who)});
            else if (text == "I am not guilty.")
                st.push_back({id.at(who), 1, id.at(who)});
            else {
                bool done = false;
                for (auto x : id) {
                    if (text == x.first + " is guilty.") {
                        st.push_back({id.at(who), 0, x.second});
                        done = true;
                    } else if (text == x.first + " is not guilty.") {
                        st.push_back({id.at(who), 1, x.second});
                        done = true;
                    }
                }
                if (!done)
                    for (int d = 0; d < 7; d++)
                        if (text == "Today is " + days[d] + ".")
                            st.push_back({id.at(who), 2, d});
            }
        }
        vector<int> possible;
        for (int guilty = 0; guilty < M; guilty++) {
            bool found = false;
            for (int day = 0; day < 7; day++) {
                vector<int> truth(M, -1);
                bool ok = true;
                for (auto s : st) {
                    int value =
                        s.type == 2 ? day == s.arg : (s.type == 0 ? guilty == s.arg : guilty != s.arg);
                    if (truth[s.who] >= 0 && truth[s.who] != value) {
                        ok = false;
                        break;
                    }
                    truth[s.who] = value;
                }
                int lies = count(truth.begin(), truth.end(), 0),
                    unknown = count(truth.begin(), truth.end(), -1);
                if (ok && lies <= N && N <= lies + unknown) {
                    found = true;
                    break;
                }
            }
            if (found)
                possible.push_back(guilty);
        }
        if (possible.empty())
            cout << "Impossible\n";
        else if (possible.size() > 1)
            cout << "Cannot Determine\n";
        else
            cout << names[possible[0]] << "\n";
    }
    
    • 1

    信息

    ID
    2004
    时间
    1000ms
    内存
    64MiB
    难度
    普及
    标签
    递交数
    0
    已通过
    0
    上传者