n<=20时候要想状压DP!!
n<=20时候要想状压DP!!
n<=20时候要想状压DP!!(重要的事情说三遍(因为我在状压DP上栽了3次。。。))
题意: 现有n盏灯,以及m个按钮。每个按钮可以同时控制这n盏灯——按下了第i个按钮,对于所有的灯都有一个效果。
按下i按钮对于第j盏灯,是下面3中效果之一:
1、如果a[i][j]为1,那么当这盏灯开了的时候,把它关上,否则不管;
2、如果为-1的话,如果这盏灯是关的,那么把它打开,否则也不管;
3、如果是0,无论这灯是否开,都不管。
现在这些灯都是开的,给出所有开关对所有灯的控制效果,求问最少要按几下按钮才能全部关掉。
以f[i]代表到达i状态的最小步数
f[(1<<n)-1]=0;
模拟转移
#include<cstdio> #include<iostream> #include<cstring> #include<cctype> #include<algorithm> using namespace std; #define olinr return #define _ 0 #define love_nmr 0 #define DB double inline int read() { int x=0,f=1; char ch=getchar(); while(!isdigit(ch)) { if(ch=='-') f=-f; ch=getchar(); } while(isdigit(ch)) { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); } return x*f; } inline void put(int x) { if(x<0) { x=-x; putchar('-'); } if(x>9) put(x/10); putchar(x%10+'0'); } int n; int m; int c[120][120]; int f[16385]; inline void dfs(int zt) { for(int i=1;i<=m;i++) { int ls=zt; for(int j=1;j<=n;j++) { if(c[i][j]==1) { if((1<<(j-1))&ls) //这一位是1 ls^=(1<<(j-1)); } else if(c[i][j]==-1) { if(!((1<<(j-1))&ls)) //这一位是0 ls^=(1<<(j-1)); } } if(f[ls]>f[zt]+1) { f[ls]=f[zt]+1; dfs(ls); } } } int main() { n=read(); memset(f,0x7f,sizeof f); f[(1<<(n))-1]=0; m=read(); for(int i=1;i<=m;i++) for(int j=1;j<=n;j++) c[i][j]=read(); dfs((1<<(n))-1); put(f[0]==0x7f7f7f7f? -1:f[0]); olinr ~~(0^_^0)+love_nmr; }