1. 程式人生 > >POJ1222 - EXTENDED LIGHTS OUT(熄燈問題)(二進位制列舉)

POJ1222 - EXTENDED LIGHTS OUT(熄燈問題)(二進位制列舉)

POJ1222 - EXTENDED LIGHTS OUT(熄燈問題)(二進位制列舉)


題目連結

題目大意

有一個由按鈕組成的矩陣,其中每行有6個按鈕,共5行。每個按鈕的位置上有一盞燈。當按下一個按鈕後,該按鈕以及周圍位置(上邊、下邊、左邊、右邊)的燈都會改變一次。即,如果燈原來是點亮的,就會被熄滅;如果燈原來是熄滅的,則會被點亮。在矩陣角上的按鈕改變3盞燈的狀態;在矩陣邊上的按鈕改變4盞燈的狀態;其他的按鈕改變5盞燈的狀態。

對矩陣中的每盞燈設定一個初始狀態。請你按按鈕,直至每一盞等都熄滅。與一盞燈毗鄰的多個按鈕被按下時,一個操作會抵消另一次操作的結果。

Sample Input


5行組成,每一行包括6個數字(01)。相鄰兩個數字之間用單個空格隔開。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個數字(01)。相鄰兩個數字之間用單個空格隔開。其中的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位來確定這個字元;
  • 設定三個函式getBitsetBitflipBit分配來獲取字元的第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;
}