1 条题解

  • 0

    题意分析:

    给出n个开关和n个人,每个人可以控制一些开关,现在所有的开关都是关着的 一个指令可以让一个人掰动所有属于他控制的开关,使得开关的状态变化, 现在要求求出最少的指令,使得开关全开,按字典序输出指令的人

    解题思路:

    我们将人的操作作为变元建立方程组,因为一个人相同的两次操作对结果是没有影响的 可以认为这是无效操作,所以每个人操作的次数只是一次或者零次, 解01方程组即可得到答案。

    实现步骤

    建模为线性方程组:

    将阀门状态变化表示为模2的线性方程组。 设每个阀门为一个方程,初始状态为0(关闭)。 每个技术人员对应一个变量(0或1,表示是否选择)。 目标状态为全1(所有阀门打开)。

    高斯消元法:

    解模2的线性方程组,找到最小解。 消元后,自由变量取0以保证解最小。 主元列对应的变量即为解

    #include <iostream>
    #include <vector>
    #include <algorithm>
    #include <cstring>
    
    using namespace std;
    
    const int MAXN = 255;
    int N;
    vector<int> technicians[MAXN]; // 每个技术员负责的阀门
    vector<int> valve_techs[MAXN]; // 每个阀门被哪些技术员负责
    bool used[MAXN]; // 标记技术员是否被选中
    vector<int> current, best;
    
    // 检查当前选中的技术员是否能覆盖所有阀门
    bool check() {
        bool valves_open[MAXN] = {false};
        for (int i = 0; i < current.size(); ++i) {
            int tech = current[i];
            for (int j = 0; j < technicians[tech].size(); ++j) {
                int valve = technicians[tech][j];
                valves_open[valve] = !valves_open[valve];
            }
        }
        for (int i = 1; i <= N; ++i) {
            if (!valves_open[i]) {
                return false;
            }
        }
        return true;
    }
    
    // 回溯法寻找最小的技术员组合
    void backtrack(int pos, int start) {
        if (pos > N) return;
        if (check()) {
            if (best.empty() || current.size() < best.size()) {
                best = current;
            }
            return;
        }
        for (int i = start; i <= N; ++i) {
            if (!used[i]) {
                used[i] = true;
                current.push_back(i);
                backtrack(pos + 1, i + 1);
                current.pop_back();
                used[i] = false;
            }
        }
    }
    
    int main() {
        cin >> N;
        for (int i = 1; i <= N; ++i) {
            int valve;
            while (cin >> valve, valve != -1) {
                technicians[i].push_back(valve);
                valve_techs[valve].push_back(i);
            }
        }
        
        backtrack(0, 1);
        
        if (best.empty()) {
            cout << "No solution" << endl;
        } else {
            sort(best.begin(), best.end());
            for (int i = 0; i < best.size(); ++i) {
                if (i != 0) cout << " ";
                cout << best[i];
            }
            cout << endl;
        }
        
        return 0;
    }
    
    • 1