[VIJOS1197] 费解的开关
枚举第一行的点击方案。
则点完后剩余的黑灯只能由第二行同一列的点击来弥补
并且第二行除了弥补第一行的黑灯之外,不能点其他灯,否则会使第一行的灯灭
上述构成了递推关系,则递推到最后一行即可。
二进制位运算优化;注意最后一行的状态的判断
复杂度 \(O(n2^n),n=5\).
代码
#include<cstdio>
#include<algorithm>
using namespace std;
int n;
int fl[10];
int bitcount(int x){// 统计 x 的二进制下 1 的个数
x=(x&0x55555555)+(x>>1&0x55555555);
x=(x&0x33333333)+(x>>2&0x33333333);
x=(x&0x0f0f0f0f)+(x>>4&0x0f0f0f0f);
x=(x&0x00ff00ff)+(x>>8&0x00ff00ff);
x=(x&0x0000ffff)+(x>>16&0x0000ffff);
return x;
}
int main(){scanf("%d",&n);
while(n--){
int ans=0x3f3f3f3f;
for(int i=1;i<=5;i++){fl[i]=0;int a;
for(int j=1;j<=5;j++)scanf("%1d",&a),fl[i]=fl[i]<<1|(a^1);
}//input
for(int i=0;i<32;i++){// 枚举第一行的点击状态
int s=i,tot=0,t[10];
for(int j=1;j<=5;j++)t[j]=fl[j];
for(int j=1;j<=5;j++){// 枚举每一行
// 当前行的点击状态为 s,则对于下一行的改变为 t[j+1]^s.
// 对当前行的改变为 t[j] ^ s<<1^s^s>>1 .
// 这时,当前行剩下的黑灯即为下一行的点击状态
t[j]=(t[j]^s<<1^s^s>>1)&((1<<5)-1);
t[j+1]=(t[j+1]^s)&((1<<5)-1);
tot+=bitcount(s&((1<<5)-1));
s=t[j];
}
if(s==0)ans=min(ans,tot);// 最后一行没有残留的 0
}
printf("%d\n",ans>6?-1:ans);
}
return 0;
}