POJ1222 - EXTENDED LIGHTS OUT(熄灯问题)(二进制枚举)
题目链接
题目大意
有一个由按钮组成的矩阵,其中每行有6个按钮,共5行。每个按钮的位置上有一盏灯。当按下一个按钮后,该按钮以及周围位置(上边、下边、左边、右边)的灯都会改变一次。即,如果灯原来是点亮的,就会被熄灭;如果灯原来是熄灭的,则会被点亮。在矩阵角上的按钮改变3盏灯的状态;在矩阵边上的按钮改变4盏灯的状态;其他的按钮改变5盏灯的状态。
对矩阵中的每盏灯设置一个初始状态。请你按按钮,直至每一盏等都熄灭。与一盏灯毗邻的多个按钮被按下时,一个操作会抵消另一次操作的结果。
Sample Input
5行组成,每一行包括6个数字(0或1)。相邻两个数字之间用单个空格隔开。0表示灯的初始状态是熄灭的,1表示灯的初始状态是点亮的。
2
0 1 1 0 1 0
1 0 0 1 1 1
0 0 1 0 0 1
1 0 0 1 0 1
0 1 1 1 0 0
0 0 1 0 1 0
1 0 1 0 1 1
0 0 1 0 1 1
1 0 1 1 0 0
0 1 0 1 0 0
Sample Output
5行组成,每一行包括6个数字(0或1)。相邻两个数字之间用单个空格隔开。其中的1表示需要把对应的按钮按下,0则表示不需要按对应的按钮。
PUZZLE #1
1 0 1 0 0 1
1 1 0 1 0 1
0 0 1 0 1 1
1 0 0 1 0 0
0 1 0 0 0 0
PUZZLE #2
1 0 0 1 1 1
1 1 0 0 0 0
0 0 0 1 0 0
1 1 0 1 0 1
1 0 1 1 0 1
解析
如果枚举每一个格子的每两个状态,就会有230种状态,会超时。
正确的做法是只需要枚举第一行的状态,然后依次往下面去影响下面的行,只枚举一行的话,只需要26 = 64种状态,可以使用二进制枚举的方式来进行枚举:
- 使用一个字符数组保存每一行的一个状态即可,因为这个数最大不会超过 26,每一个字符保存的是一行的状态,因为可以使用一行
6位来确定这个字符; - 设定三个函数
getBit、setBit、flipBit分配来获取字符的第i位、设置字符的第i位、翻转字符的第i位。 - 然后按照枚举每一行,然后去影响旁边和下一行的方式,总共枚举
64种即可,如果枚举到第5行,这一行的灯都是0(灭)的话,这个方案就可以,记得使用一个字符数组记录结果,最后打印即可。
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.PrintWriter;
import java.util.Scanner;
public class Main {
private static int getBit(char c, int i){
return (c >> i) & 1;
}
private static void setBit(char[] lights, int i, int j, int val){
lights[i] = (char) (val == 1 ? lights[i]|(1<<j): lights[i]&(~(1<<j)));
}
private static void flipBit(char[] lights, int i, int j){
lights[i] ^= (1 << j);
}
private static void printResult(int t, char[] res, PrintWriter out){
out.println(\"PUZZLE #\" + t);
for(int i = 0; i < 5; ++i){
for(int j = 0; j < 6; ++j){
out.print(getBit(res[i], j));
if(j < 5)
out.print(\" \");
}
out.println();
}
}
private static void solve(Scanner in, PrintWriter out){
char[] oriLight = new char[5];
char[] lights = new char[5];
char[] res = new char[5];
int T, num;
T = in.nextInt();
for(int t = 1; t <= T; ++t) {
for (int i = 0; i < 5; ++i) {
for (int j = 0; j < 6; ++j) {
num = in.nextInt();
setBit(oriLight, i, j, num);
}
}
for(int n = 0; n < 64; n++) {
int switchs = n;
System.arraycopy(oriLight, 0, lights, 0, oriLight.length);
for (int i = 0; i < 5; ++i) {
res[i] = (char) switchs;
for (int j = 0; j < 6; ++j) {
if (1 == getBit((char)switchs, j)) {
flipBit(lights, i, j);
if (j > 0)
flipBit(lights, i, j - 1);
if (j < 5)
flipBit(lights, i, j + 1);
}
}
if(i < 4)
lights[i+1] ^= switchs;
switchs = lights[i];
}
if (lights[4] == 0) {
printResult(t, res, out);
break;
}
}
}
}
public static void main(String[] args){
Scanner cin = new Scanner(new BufferedInputStream(System.in));
//try {
// cin = new Scanner(new FileInputStream(\"in.txt\"));
//} catch (FileNotFoundException e) {
// e.printStackTrace();
//}
PrintWriter out = new PrintWriter(System.out);
long start = System.nanoTime();
solve(cin, out);
long end = System.nanoTime();
//System.out.println(\"Time elapsed: \" + (end - start)/1000000000.0);
out.close();
}
}
C++代码:
#include <iostream>
#include <string.h>
int getBit(char c, int i){ //取c的第i位
return (c>>i) & 1;
}
void setBit(char &c, int i, int val){ //给c的第i位设置成val(0/1)
c = val ? c|(1<<i) : c&(~(1<<i));
}
void flipBit(char &c, int i){ // 将c的第i位翻转
c ^= (1 << i); //不同为1相同为0, 原先是1 ^ 1--> 0, 原先是0^1 --> 1
}
void printResult(int t, const char* res){
std::cout << \"PUZZLE #\" << t << std::endl;
for(int i = 0; i < 5; i++){
for(int j = 0; j < 6; j++){
std::cout << getBit(res[i], j);
if(j < 5)
std::cout << \" \";
}
std::cout << std::endl;
}
}
int main(int argc, char const** argv)
{
std::ios::sync_with_stdio(false);
std::cin.tie(0);
int T, num;
char oriLights[5], lights[5], res[5];
std::cin >> T;
for(int t = 1; t <= T; t++){
for(int i = 0; i < 5; i++){ // 5 row
for(int j = 0; j < 6; j++){ // 6 col
std::cin >> num;
setBit(oriLights[i], j, num);
}
}
// 枚举当前的行,去处理下面的行,二进制枚举总共有2^6 = 64
for(int n = 0; n < 64; n++){
int tmpN = n; // cur row\'s result
memcpy(lights, oriLights, sizeof(oriLights));
for(int i = 0; i < 5; i++){
res[i] = tmpN; // record the result
for(int j = 0; j < 6; j++){
if(getBit(tmpN, j)){ //judge curPosition is 1, to influence next to self
flipBit(lights[i], j); // self filp
if(j > 0)
flipBit(lights[i],j-1); // left filp
if(j < 5)
flipBit(lights[i],j+1); // right flip
}
}
//curRows influence next row (important) ---> down flip
if(i < 4) // 5 rows in total
lights[i+1] ^= tmpN;
tmpN = lights[i]; // update tmpN
}
if(lights[4] == 0){
printResult(t, res);
break;
}
}
}
return 0;
}
继续阅读与本文标签相同的文章
上一篇 :
证书转换
下一篇 :
油烟净化器十大品牌真假如何辨别
-
功耗问题之后台过多WIFI 扫描
2026-05-18栏目: 教程
-
曾经风靡一时的360安全卫士为什么如今没落了?
2026-05-18栏目: 教程
-
用C语言编程,如何节省存储空间?
2026-05-18栏目: 教程
-
三元牛奶,的优势在哪里?
2026-05-18栏目: 教程
-
常浏览“成人网站”要留意了,有这2种反应,请立马关闭
2026-05-18栏目: 教程
