P2622 关灯问题II ( 状压 + bfs

#include 
using namespace std;
using VI = vector;
int n,m;
int close[110];
int open[110];
int dp[1 << 12];
int vis[1 << 12];
//n个灯  m 个 按钮
// n <=  10
//dp[0] =  0;
//按下一个按钮 , 先把状态 |    开灯  把 (0 , 1) 变成 1 ,(1 , 1) 还是 1 , 110   101   111 
//现在                        关灯     (1 , 0) 变成 0   (1 , 1) 变成 1  (0 , 0) 变成 0
// 110    101       010
int main(){
    cin>>n>>m;
    for(int i = 0 ; i < m ; i++){
         //close[i] = (1 << n) - 1;
        for(int j = 0 ; j < n ; j++){
            int x;
            cin>>x;
            if(x == 0) continue;
            else if (x == 1) close[i] |= (1 << j);
            else if (x == -1) open[i] |= (1 << j);
            //记录一下第 i 个 开关可以关哪些灯 , 开哪些灯
        }
    }
    vis[(1 << n) - 1 ] = 1;
    queue q;
    q.push((1<

状压 + bfs ,记录每个开关的open 和 close 情况

open 比较简单 直接 st | open[i]   ,

关灯只有同时为 1 时  才关灯 , 其他状态都保持不变,直接枚举同时为1

如果开的紧不让枚举,可以考虑把 close 情况的 0 1倒过来取

时间复杂度 n * n * (1 << n)  层数少  ,跑的飞快,  n <= 10

而且这题不是一个常规的枚举状态,从前序状态中转移,一个状态可以从后和也可以从前的状态转移

结合这题是求最小步数 同时 一个按钮 连续按两次是没有意义的,不难想到到达一个状态的时间越早越好,这很显然是一个bfs

你可能感兴趣的:(算法,数据结构,图论)