POJ1222 - EXTENDED LIGHTS OUT(熄燈問題)(二進位制列舉)
阿新 • • 發佈:2019-01-07
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.*;
import java.util.Scanner;
import java.util.StringTokenizer;
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(FastReader 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;
}
}
}
}
private static class FastReader{
public BufferedReader br;
public StringTokenizer st;
public FastReader(InputStream is){
br = new BufferedReader(new InputStreamReader(is));
st = null;
}
String next(){
while(st == null || !st.hasMoreElements()){
try {
st = new StringTokenizer(br.readLine());
} catch (IOException e) {
e.printStackTrace();
}
}
return st.nextToken();
}
public int nextInt(){
return Integer.parseInt(next());
}
public long nextLong(){
return Long.parseLong(next());
}
public double nextDouble(){
return Double.parseDouble(next());
}
public String nextLine(){
String str = "";
try {
str = br.readLine();
} catch (IOException e) {
e.printStackTrace();
}
return str;
}
}
public static void main(String[] args){
// Scanner fr = new Scanner(new BufferedInputStream(System.in));
// try {
// fr = new Scanner(new FileInputStream("/home/zxzxin/Java_Maven/Algorithm/src/main/java/ACM/Other/in.txt"));
// } catch (FileNotFoundException e) {
// e.printStackTrace();
// }
// more fast
FastReader fr = new FastReader(new BufferedInputStream(System.in));
// try {
// fr = new FastReader(new FileInputStream("/home/zxzxin/Java_Maven/Algorithm/src/main/java/ACM/Other/in.txt"));
// } catch (FileNotFoundException e) {
// e.printStackTrace();
// }
PrintWriter out = new PrintWriter(System.out);
long start = System.nanoTime();
solve(fr, 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;
}