問題の説明:
これは、ランプの各ボタンの位置は、各行が6つのボタンを有するボタンのマトリックス、5行の合計がありました
ボタンが押されると、ボタンの位置と周囲(右、左、下、上)の光が一度変更され
ランプが最初に点灯している場合、それは消滅するだろう
ランプが消灯し、点灯された場合
入力:
ケース、ケース5行を入力し、スペースで区切られている6桁の数字を含む各行は、0または1.0であることができるランプの初期状態が消滅する表し、1の初期状態は、ランプが点灯していることを示し。
出力:
5例の出力ラインの入力形式に従って、1 0は、スペースで区切られた各番号に対応するボタンを押す必要がないことを示し、対応するボタンを押す必要性を示しています。
例1:
サンプル入力:
出力例:
例2:
サンプル入力:
出力例:
分析:
問題の分析:
この問題は、制限はランプのような回数はないが、ボタンが点灯を押して、オフに私たちを必要としますが、同じボタンの第2のプレスが最初のキーを押して結果を生み出しキャンセルされますので、時間のみを押すまでは、(有意でしたそれは)プレスと等価ではないため、
大幅にプレスを押すか、ではありません。第二に、注文ボタンに影響を与えるが押下され、衝撃の現在の状態があり、最終結果に影響は、後述ありません。
話題の分析の後番組の限られた数の様々な状況、見つけることができ、解空間が限られているということなので、すべてのボタンのケースの作業を列挙し、その後、列挙アルゴリズムを使用することを検討してください?
- ボタンの二つの状態(押され又は押されていない)、6×5 = 30のスイッチの合計があり、状態の数に対応する2 ^ 30であり、明らかに非常に時間がかかり、望ましくありません。
解空間が一定であるので、我々は、解空間を狭くする方法がありませんか?
基本的な考え方:
ローカルの状態がある場合はローカル状態が与えられた後、残りのいくつかの状態しか判断することができるので、我々は唯一のローカルな状態を列挙する必要があります。
実際、そのような局所的な状態は、我々の目的は、すべてのライトがオフになっていることであるので、最初の行の状態が決定される最初の行のように、存在しない、最初の行は、第1貫通消滅ランプありませんそれ以前の2行は、2行目、3行目共感をオフにすることができ...
5行目が真である、最後に、(保証続く最初の4行がオフラインであるため、唯一の5行目を保証することができない、)すべてのライトがオフであるかどうかを決定するために第5行の状態に応じて、trueの場合、それは有効です解決策は、状況の次のセットを列挙し続けますか。
在这个方法中,我们只枚举第一行(事实上第一列也是可行的,且效率更高),状态数仅为2^6=64种,在效率上足以令人满意。
实现方法:
首先建立两个二维矩阵,用于存储puzzle(灯的初始状态)和press(按钮的状态),为了简化矩阵左右上下边界的代码量以及index与序号对应,将矩阵从5*6扩充为6*8,并初始化为0。
接着,我们需要枚举第一行的所有情况,传统的办法是写6个for循环,但这显然不是个好办法(比如矩阵是100列),观察发现,矩阵中每一个元素的取值只能是0/1,对第一行整体观察,其取值范围为
从000 000,到111 111(二进制),对应于十进制的0到63,因此,我们可以枚举一个整型变量,它从0自增到63,然后用位运算分解赋到相应的位置。
对于枚举的每一种情况,都要判断该情况是否可行,具体方法是,由于第一行的状态已经由分解给定,逐行分析第2行到第5行,最后判断第5行的puzzle是否为全0,如果是则输出press并返回,
否则继续枚举下一组情况,如果枚举了全部情况但不存在解,则输出“无解”。
代码(c++):
1 #include <iostream> 2 #include <string.h> 3 using namespace std; 4 int puzzle[6][8] = {0}; 5 int puzzle_copy[6][8]; 6 int press[6][8] = {0}; 7 void Initialize(); //对puzzle初始化 8 void Breakdown(int); //分解整型变量,并赋给相应位置 9 bool Guess(); //测试当前分解情况是否可行,可行则返回true,否则返回false 10 void Execute(int, int); //执行第i行第j列按下操作 11 void Print(); //打印Press矩阵 12 int main() 13 { 14 Initialize(); 15 int i; 16 for (i = 0; i < 64; ++i) { 17 memcpy(puzzle, puzzle_copy, sizeof(puzzle)); 18 Breakdown(i); 19 if (Guess()) { 20 Print(); 21 break; 22 } 23 } 24 if (i == 64) 25 cout << "无解\n" << endl; 26 return 0; 27 } 28 29 void Initialize() 30 { 31 //用户输入5*6矩阵 32 freopen("input.txt", "r", stdin); 33 for (int i = 1; i < 6; ++i) 34 for (int j = 1; j < 7; ++j) 35 cin >> puzzle[i][j]; 36 memcpy(puzzle_copy, puzzle, sizeof(puzzle)); 37 } 38 39 void Breakdown(int x) 40 { 41 int i = 6; 42 while (x > 0) { 43 press[1][i] = x & 1; 44 Execute(1, i--); 45 x >>= 1; 46 } 47 } 48 49 bool Guess() 50 { 51 for (int i = 2; i < 6; ++i) { 52 for (int j = 1; j < 7; ++j) { 53 if (puzzle[i - 1][j] == 1) { 54 press[i][j] = 1; 55 Execute(i, j); 56 } 57 else 58 press[i][j] = 0; 59 } 60 } 61 for (int i = 1; i < 7; ++i) { 62 if (puzzle[5][i] == 1) 63 return false; 64 } 65 return true; 66 } 67 68 void Execute(int i, int j) 69 { 70 if (press[i][j] == 1) { 71 puzzle[i][j] ^= 1; //取反 72 puzzle[i - 1][j] ^= 1; 73 puzzle[i][j - 1] ^= 1; 74 puzzle[i][j + 1] ^= 1; 75 puzzle[i + 1][j] ^= 1; 76 } 77 } 78 79 void Print() 80 { 81 cout << "press结果为:" << endl; 82 for (int i = 1; i < 6; ++i) { 83 for (int j = 1; j < 7; ++j) { 84 cout << press[i][j] << ' '; 85 } 86 cout << endl; 87 } 88 }
注意:这里的输入流重定向到了input.txt文件,为了调试的方便。