[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;
}
posted @ 2019-06-15 08:15  Sshwy  阅读(87)  评论(0编辑  收藏  举报