题目描述
现有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
我们设一个二进制数s当第j个灯开着时s的第j位是1关闭时是0,由于n非常小,我们就可以用十进制数表示出所有状态,所以我们考虑直接暴力搜索,对每一种n的状态进行标记,放进v数组中判断,保证每个状态值找一遍,非常暴力,bfs每次枚举开哪一个开关,第一次找到状态为0的时候就是答案,
这样的话复杂度是
O
(
2
n
∗
m
)
O(2^n*m)
O(2n∗m)是可以接受的
C
o
d
e
Code
Code
#include<bits/stdc++.h>
#define N 1001
#define MAXN 1000010
#define INF 0x3f3f3f3f
#define ll long long
#define gtc() getchar()
using namespace std;
template <class T>
inline void read(T &s){
s = 0; T w = 1, ch = gtc();
while(!isdigit(ch)){if(ch == '-') w = -1; ch = gtc();}
while(isdigit(ch)){s = s * 10 + ch - '0'; ch = gtc();}
s *= w;
}
inline void write(ll x){
if(x < 0) putchar('-'), x = -x;
if(x > 9) write(x/10);
putchar(x % 10 + '0');
}
int n, m;
int a[101][101];
struct node {
int s, stp;
};
queue<node> q;
int v[MAXN];
bool flg = 0;
int bfs(int s, int stp){
node x; x.s = s, x.stp = stp;
q.push(x);
// if(flg) return 0;
while (!q.empty()) {
x = q.front(); q.pop();
if (!x.s) return x.stp;
for(int i = 1; i <= m; ++i){
int ss = x.s;
for(int j = 1; j <= n; ++j){
if((a[i][j] == 1) && (ss & (1 << (j - 1)))) {
ss = ss ^ (1 << (j-1));
}
else if((a[i][j] == -1) && !((ss & (1 << (j - 1))))) {
ss = ss | (1<<(j-1));
}
}
if(v[ss]) continue;
node y; y.s = ss, y.stp = x.stp + 1;
v[ss] = 1;
q.push(y);
}
}
return -1;
}
int main()
{
read(n), read(m);
for(int k = 1; k <= m; ++k)
for(int i = 1; i <= n; ++i){
read(a[k][i]);
}
int s = (1<<n)-1;
v[s] = 1;
printf("%d\n", bfs(s, 0));
return 0;
}