洛谷

洛谷题单指南-状态压缩动态规划-P2622 关灯问题 II

原题链接:https://www.luogu.com.cn/problem/P2622

题意解读:求将所有灯都关掉最少按钮次数。

解题思路:

典型的最小步数模型,灯的状态采用状态压缩,然后通过BFS即可求得最少步数。

初始状态所有灯都开:(1 << n) - 1

对于每一个状态,枚举所有的开关,转移到目标状态,直到为0。

100分代码:

#include <bits/stdc++.h>
using namespace std;

const int N = 11, M = 105, INF = 0x3f3f3f3f;
int a[M][N];
int d[1 << N];
bool vis[1 << N];
int n, m, ans;

void bfs()
{
    int s = (1 << n) - 1; //初始状态
    queue<int> q;
    q.push(s);
    vis[s] = true;
    d[s] = 0;
    while(q.size())
    {
        int x = q.front(); 
        q.pop();
        for(int i = 0; i < m; i++) //枚举所有开关
        {
            int y = 0;
            for(int j = 0; j < n; j++) //计算目标状态
            {
                if(a[i][j] == -1 && !(x >> j & 1)) y |= 1 << j; 
                else if(a[i][j] == 1 && (x >> j & 1));
                else if(x >> j & 1) y |= 1 << j;
            }
            if(vis[y]) continue;
            d[y] = d[x] + 1; //步数加1
            if(y == 0) return; //找到结果状态
            q.push(y);
            vis[y] = true;
        }
    }
}

int main()
{
    cin >> n >> m;
    for(int i = 0; i < m; i++)
        for(int j = 0; j < n; j++)
            cin >> a[i][j];
    memset(d, 0x3f, sizeof(d));
    bfs();
    if(d[0] != INF) cout << d[0];
    else cout << -1;

    return 0;
}