📜  门|门CS 2011 |问题 22(1)

📅  最后修改于: 2023-12-03 14:58:37.273000             🧑  作者: Mango

门|门CS 2011 |问题 22 简介

题目描述:给定四个门和一个机关,机关只能当门都关上时才能打开,每次可以选择其中两个门,如果它们都开着就把它们都关上,否则就把它们都打开。

我们需要写一个程序来模拟这个过程,即输入起始状态(门的开闭状态),输出最终状态(机关是否打开)。

解题思路

这是一道典型的状态搜索问题,我们可以用一个长度为16的二进制数来表示当前状态,其中每一位代表一个门的开闭状态,0表示门关闭,1表示门开启。

先定义一个函数operator(state,a,b),输入当前状态state和选中的两个门的编号ab,返回更新后的状态。

具体实现是:首先判断ab门的状态,如果两个门都是开着的,就把它们全部关闭;如果两个门都是关着的,就把它们全部打开;否则的话就不用管它们了。

定义一个队列q,并将起始状态加入队列。

用一个unordered_set(C++11中的一种哈希表,可以在常数时间内判断一个元素是否在集合中)来保存已经搜索过的状态。每次从队列中取出一个状态,判断它是否是目标状态(即所有门都关闭),如果是,就直接返回;否则枚举两个门的组合,得到新状态,如果新状态没有搜索过就加入队列,并把它标记为已搜索过。

最终如果整个队列都被搜索完了还没有找到目标状态,就说明无解。

代码实现
struct State {
    unsigned short value;

    bool operator<(const State& rhs) const {
        return value < rhs.value;
    }
};

State operator&(const State& lhs, const State& rhs) {
    return {lhs.value & rhs.value};
}

State operator~(const State& state) {
    return {~state.value};
}

bool operator==(const State& lhs, const State& rhs) {
    return lhs.value == rhs.value;
}

bool operator!=(const State& lhs, const State& rhs) {
    return lhs.value != rhs.value;
}

State operator^(const State& lhs, const State& rhs) {
    return {lhs.value ^ rhs.value};
}

State operator|(const State& lhs, const State& rhs) {
    return {lhs.value | rhs.value};
}

State operator|(const State& lhs, unsigned short rhs) {
    return {lhs.value | rhs};
}

State operator<<(const State& lhs, int rhs) {
    return {lhs.value << rhs};
}

State operator>>(const State& lhs, int rhs) {
    return {lhs.value >> rhs};
}

State operator+(const State& lhs, const State& rhs) {
    return lhs ^ rhs;
}

bool IsDoorOpen(const State& state, int idx) {
    return state.value & (1 << idx);
}

State CloseDoor(State state, int idx) {
    state.value &= ~(1 << idx);
    return state;
}

State OpenDoor(State state, int idx) {
    state.value |= (1 << idx);
    return state;
}

State operator|(const State& lhs, const std::vector<int>& rhs) {
    State result = lhs;
    for (int idx : rhs) {
        result = OpenDoor(result, idx);
    }
    return result;
}

int bfs(State start) {
    std::unordered_set<State> visited;
    std::queue<State> q;
    q.push(start);
    visited.insert(start);

    while (!q.empty()) {
        State cur_state = q.front();
        q.pop();

        bool all_closed = true;
        for (int i = 0; i < 4; ++i) {
            if (IsDoorOpen(cur_state, i)) {
                all_closed = false;
                break;
            }
        }
        if (all_closed) {
            return 0;
        }

        for (int i = 0; i < 4; ++i) {
            for (int j = i + 1; j < 4; ++j) {
                State new_state = operator|(cur_state, std::vector{i, j});
                if (visited.count(new_state) == 0) {
                    q.push(new_state);
                    visited.insert(new_state);
                }
            }
        }
    }

    return -1;
}

int main() {
    int start_state = 0;
    for (int i = 0; i < 4; ++i) {
        char c;
        std::cin >> c;
        if (c == '1') {
            start_state |= (1 << i);
        }
    }

    int res = bfs(State{start_state});

    if (res == -1) {
        std::cout << "impossible" << std::endl;
    } else {
        std::cout << res << std::endl;
    }

    return 0;
}

markdown标记:代码用三个撇括起来,并指定语言(本程序是C++);公式用一个撇括起来。

// 代码放在这里

$E=mc^2$