题目描述
题目
现有 n n n盏灯,以及 m m m个按钮。每个按钮可以同时控制这 n n n盏灯——按下了第 i i i个按钮,对于所有的灯都有一个效果。按下 i i i按钮对于第 j j j盏灯,是下面 3 3 3中效果之一:如果 a [ i ] [ j ] a[i][j] a[i][j]为 1 1 1,那么当这盏灯开了的时候,把它关上,否则不管;如果为 − 1 -1 −1的话,如果这盏灯是关的,那么把它打开,否则也不管;如果是 0 0 0,无论这灯是否开,都不管。
现在这些灯都是开的,给出所有开关对所有灯的控制效果,求问最少要按几下按钮才能全部关掉。
输入格式
前两行两个数, n m n m nm
接下来 m m m行,每行 n n n个数, a [ i ] [ j ] a[i][j] a[i][j]表示第 i i i个开关对第 j j j个灯的效果。
输出格式
一个整数,表示最少按按钮次数。如果没有任何办法使其全部关闭,输出 − 1 -1 −1
输入输出样例
输入 #1
3
2
1 0 1
-1 1 0
输出 #1
2
分析:
状压 D P DP DP永( z h e n zhen zhen)远( d e de de)滴( e e e)神( x i n xin xin) ! ! ! ! !!!! !!!!
看到你谷有 B F S BFS BFS解法的 我只能 %%% 谁让蒟蒻的我只能用状压 D P DP DP呢?
n , m n,m n,m都很小 就考虑状压 D P DP DP 设 f [ i ] f[i] f[i]表示灯到 i i i状态最少步数
枚举 0 0 0 1 1 1 − 1 -1 −1三种状态 用一个变量 x x x累加步数 然后 D P : DP: DP:
f [ x ] = m i n ( f [ x ] , f [ i ] + 1 ) f[x]=min(f[x],f[i]+1) f[x]=min(f[x],f[i]+1)
CODE:
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int n,m,a[1005][15],f[2049];
int main(){
scanf("%d%d",&n,&m);
memset(f,0x3f,sizeof(f));
for(int i=1;i<=m;i++)
for(int j=1;j<=n;j++)
scanf("%d",&a[i][j]);
f[0]=0;
for(int i=0;i<=(1<<n)-1;i++) //枚举 1(1<<n)-1为二进制转换成十进制状态
for(int j=1;j<=m;j++)
{
int qaq=i;
for(int qwq=0;qwq<n;qwq++)
{
if(a[j][qwq+1]==0) continue; //优化 0就不用做
if(a[j][qwq+1]==-1&&(i&1<<qwq)||a[j][qwq+1]==1&&!(i&1<<qwq)) //其他两种状态
qaq^=(1<<(qwq)); //累加
}
f[qaq]=min(f[qaq],f[i]+1); //DP
}
printf("%d",f[(1<<n)-1]==0x3f3f3f3f?-1:f[(1<<n)-1]); //三目压行
return 0;
}