当前位置:首页 > 比赛题解 > 2023年CSP-S密码锁(洛谷P9752):集合运算与候选筛选策略

2023年CSP-S密码锁(洛谷P9752):集合运算与候选筛选策略

10小时前比赛题解44

截图未命名.jpg 2023年CSP-S密码锁(洛谷P9752):集合运算与候选筛选策略 CSP-S 密码锁 集合运算 提高组 竞赛题解 洛谷题解 C++ 第1张

一、问题背景

2023年CSP-S竞赛密码锁问题要求通过观察多个异常状态,推断出原始正确密码的可能组合。密码锁由5个拨圈组成,每次操作可以是单拨圈转动或相邻双拨圈同步转动。

二、核心算法解析

1. 候选密码生成

set<vector<int>> generate_candidates(const vector<int>& state) {
    set<vector<int>> candidates;
    // 单拨圈操作:每个拨圈独立转动-9到9格(除0)
    for (int i = 0; i < 5; ++i) {
        for (int delta = -9; delta <= 9; ++delta) {
            if (delta == 0) continue;
            vector<int> candidate = state;
            candidate[i] = (candidate[i] - delta + 20) % 10; // +20处理负数取模
            candidates.insert(candidate);
        }
    }
    // 双拨圈操作:相邻两个拨圈同步转动
    for (int i = 0; i < 4; ++i) {
        for (int delta = -9; delta <= 9; ++delta) {
            if (delta == 0) continue;
            vector<int> candidate = state;
            candidate[i] = (candidate[i] - delta + 20) % 10;
            candidate[i+1] = (candidate[i+1] - delta + 20) % 10;
            candidates.insert(candidate);
        }
    }
    return candidates;
}

2. 集合交集处理

// 取所有观察状态的候选密码交集
set_intersection(
    common_candidates.begin(), common_candidates.end(),
    current_candidates.begin(), current_candidates.end(),
    inserter(temp, temp.begin())
);

三、完整代码实现

#include <iostream>
#include <vector>
#include <set>
#include <algorithm>
using namespACe std;

// 生成所有可能的正确密码候选
set<vector<int>> generate_candidates(const vector<int>& state) {
    set<vector<int>> candidates;
    
    // 单拨圈操作
    for (int i = 0; i < 5; ++i) {
        for (int delta = -9; delta <= 9; ++delta) {
            if (delta == 0) continue;
            vector<int> candidate = state;
            candidate[i] = (candidate[i] - delta + 20) % 10;
            candidates.insert(candidate);
        }
    }
    
    // 双相邻拨圈操作
    for (int i = 0; i < 4; ++i) {
        for (int delta = -9; delta <= 9; ++delta) {
            if (delta == 0) continue;
            vector<int> candidate = state;
            candidate[i] = (candidate[i] - delta + 20) % 10;
            candidate[i+1] = (candidate[i+1] - delta + 20) % 10;
            candidates.insert(candidate);
        }
    }
    
    return candidates;
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    
    int n;
    cin >> n;
    vector<vector<int>> states(n, vector<int>(5));
    
    for (int i = 0; i < n; ++i) {
        for (int j = 0; j < 5; ++j) {
            cin >> states[i][j];
        }
    }
    
    // 第一个状态的所有候选
    set<vector<int>> common_candidates = generate_candidates(states[0]);
    
    // 与其他状态的候选取交集
    for (int i = 1; i < n; ++i) {
        set<vector<int>> current_candidates = generate_candidates(states[i]);
        set<vector<int>> temp;
        
        set_intersection(
            common_candidates.begin(), common_candidates.end(),
            current_candidates.begin(), current_candidates.end(),
            inserter(temp, temp.begin())
        );
        
        common_candidates = temp;
        if (common_candidates.empty()) break;
    }
    
    // 排除观察到的状态本身(题目说明这些不是正确密码)
    for (const auto& state : states) {
        common_candidates.erase(state);
    }
    
    cout << common_candidates.size() << endl;
    return 0;
}


原创内容 转载请注明出处

分享给朋友:

发表评论

访客

看不清,换一张

◎欢迎参与讨论,请在这里发表您的看法和观点。