題目描述
現有n盞燈,以及m個按鈕。每個按鈕可以同時控制這n盞燈——按下了第i個按鈕,對於所有的燈都有一個效果。按下i按鈕對於第j盞燈,是下面3中效果之一:如果a[i][j]爲1,那麼當這盞燈開了的時候,把它關上,否則不管;如果爲-1的話,如果這盞燈是關的,那麼把它打開,否則也不管;如果是0,無論這燈是否開,都不管。
現在這些燈都是開的,給出所有開關對所有燈的控制效果,求問最少要按幾下按鈕才能全部關掉。
輸入格式
前兩行兩個數,n m
接下來m行,每行n個數,a[i][j]表示第i個開關對第j個燈的效果。
輸出格式
一個整數,表示最少按按鈕次數。如果沒有任何辦法使其全部關閉,輸出-1
輸入輸出樣例
3 2 1 0 1 -1 1 0
2
說明/提示
對於20%數據,輸出無解可以得分。
對於20%數據,n<=5
對於20%數據,m<=20
上面的數據點可能會重疊。
對於100%數據 n<=10,m<=100
實現代碼
#include<iostream>
#include<queue>
#include<cstring>
#define Inf 0x3f3f3f3f
using namespace std;
int a[101][11], f[1 << 10], inq[1 << 10], n, m, maxn;
int spfa() {
memset(f, Inf, sizeof(f));
memset(inq, 0, sizeof(inq));
queue<int> q;
maxn = (1 << n) - 1; // 燈的狀態全爲 1
f[maxn] = 0, inq[maxn] = 1, q.push(maxn);
while (q.size()) {
int now = q.front(); inq[now] = 0, q.pop();
for (int i = 1; i <= m; i++) {
int obj = now;
for (int j = 1; j <= n; j++) {
if (a[i][j] == -1) obj |= 1 << (j - 1); // 第j位如果是0變成1,1則不變,即該位變1
if (a[i][j] == 1) obj &= maxn - (1 << (j - 1)); // 第j位如果是1變成0,0則不變,即該位變0
}
if (obj == 0) return f[now] + 1;
if (f[obj] > f[now] + 1) {
f[obj] = f[now] + 1;
if (!inq[obj]) {
inq[obj] = 1;
q.push(obj);
}
}
}
}
return -1;
}
int main() {
cin >> n >> m;
for (int i = 1; i <= m; i++) for (int j = 1; j <= n; j++) cin >> a[i][j];
cout << spfa() << endl;
return 0;
}