现有 (n) 盏灯,以及 (m) 个按钮。每个按钮可以同时控制这 (n) 盏灯——按下了第 (i) 个按钮,对于所有的灯都有一个效果。按下 (i) 按钮对于第 (j) 盏灯,是下面3中效果之一:如果 (a_{ij})为 (1),那么当这盏灯开了的时候,把它关上,否则不管;如果为 (-1) 的话,如果这盏灯是关的,那么把它打开,否则也不管;如果是 $04 ,无论这灯是否开,都不管。
现在这些灯都是开的,给出所有开关对所有灯的控制效果,求问最少要按几下按钮才能全部关掉。
对于100%数据 n<=10,m<=100.
状压dp 水题,因为难的题自己也不会做QAQ。
设 (f[i]) 表示 达到 (i) 这个状态所需要的最少的操作次数。
转移的时候枚举一下按哪一个按钮,在模拟一下得到最终的状态,然后就可以直接 (dp) 了。
上限大概是很松的,复杂度为 (O(2^nnm))
Code
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
int n,m,a[110][10],f[(1<<12)];
inline int read()
{
int s = 0,w = 1; char ch = getchar();
while(ch < '0' || ch > '9'){if(ch == '-') w = -1; ch = getchar();}
while(ch >= '0' && ch <= '9'){s = s * 10 + ch - '0'; ch = getchar();}
return s * w;
}
int main()
{
n = read(); m = read();
for(int i = 1; i <= m; i++)
{
for(int j = 1; j <= n; j++)
{
a[i][j] = read();
}
}
for(int i = 0; i < (1<<n)-1; i++) f[i] = 2333333;
f[(1<<n)-1] = 0;
for(int i = (1<<n)-1; i >= 0; i--)
{
for(int j = 1; j <= m; j++)
{
int tmp = i;
for(int k = 1; k <= n; k++)
{
if(a[j][k] == 0) continue;
if(a[j][k] == 1)
{
if(i & (1<<(k-1))) tmp = tmp & (~(1<<(k-1))); //把tmp的第k-1位赋零
}
if(a[j][k] == -1)
{
if(!(i & (1<<(k-1)))) tmp = tmp | (1<<(k-1));//把tmp的k-1位赋一
}
}
// cout<<tmp<<endl;
f[tmp] = min(f[tmp],f[i] + 1);//tmp就是按下第j个按钮变成的状态
}
}
if(f[0] == 2333333) printf("%d
",-1);
else printf("%d
",f[0]);
return 0;
}