地址 https://www.acwing.com/problem/content/118/ios
「飛行員兄弟」這個遊戲,須要玩家順利的打開一個擁有16個把手的冰箱。ide
已知每一個把手能夠處於如下兩種狀態之一:打開或關閉。spa
只有當全部把手都打開時,冰箱纔會打開。code
把手能夠表示爲一個4х4的矩陣,您能夠改變任何一個位置[i,j]上把手的狀態。xml
可是,這也會使得第i行和第j列上的全部把手的狀態也隨着改變。blog
請你求出打開冰箱所需的切換把手的次數最小值是多少。遊戲
輸入一共包含四行,每行包含四個把手的初始狀態。ci
符號「+」表示把手處於閉合狀態,而符號「-」表示把手處於打開狀態。get
至少一個手柄的初始狀態是關閉的。string
第一行輸出一個整數N,表示所需的最小切換把手次數。
接下來N行描述切換順序,每行輸入兩個整數,表明被切換狀態的把手的行號和列號,數字之間用空格隔開。
1≤i,j≤4
輸入樣例: -+-- ---- ---- -+-- 輸出樣例: 6 1 1 1 3 1 4 4 1 4 3 4 4 注意:若是存在多種打開冰箱的方式,則按照優先級總體從上到下,同行從左到右打開。
題解 沒有剪枝等捷徑 就是考覈位運算
使用int change[4][4] 記錄任意一個按鈕點擊後的變化
0~1<<16 二進制表明各類按鈕的按法組合 而後遍歷嘗試
代碼以下
1 #include <iostream> 2 #include <string> 3 #include <vector> 4 5 6 using namespace std; 7 8 typedef pair<int,int> PII; 9 10 11 int change[4][4]={0}; 12 13 int get(int x,int y){ 14 return x*4+y; 15 } 16 17 18 19 int main() 20 { 21 int state = 0; 22 for(int i = 0;i < 4;i++){ 23 string tmpStr; 24 cin >> tmpStr; 25 for(int j = 0; j < tmpStr.size();j++){ 26 if(tmpStr[j] == '+'){ 27 state += 1<<get(i,j); 28 } 29 } 30 } 31 32 //製做每次點擊某個開關後的變化表格 33 for(int i =0;i < 4;i++){ 34 for(int j = 0; j < 4;j++){ 35 for(int k = 0; k < 4;k++){ 36 change[i][j] += 1<< get(i,k); 37 change[i][j] += 1 <<get(k,j); 38 } 39 //選擇的點回增長兩次,減小1 40 change[i][j] -= 1 << get(i,j); 41 } 42 } 43 44 vector<PII> res; 45 //遍歷各類可能的點擊開關的方案 16個按鈕選出任意N個點擊 從0-16個的排列組合就是0~ 1<<16; 46 for(int k = 0;k < 1 << 16;k++){ 47 int now = state; 48 vector<PII> path; 49 //當前選擇的點擊方案 點擊了那些按鈕 50 for(int i = 0; i< 16;i++){ 51 if(k >> i & 1){ 52 //該按鈕按下了 53 int x = i/4,y = i%4; 54 now ^= change[x][y]; 55 path.push_back({x,y}); 56 } 57 if(!now && ( res.empty() || res.size() > path.size() )) 58 res = path; 59 } 60 } 61 62 cout << res.size() << endl; 63 for(auto p : res) 64 cout << p.first +1 << ' ' << p.second+1 << endl; 65 66 67 return 0; 68 }