acWing刷題記錄
阿新 • • 發佈:2022-03-20
第一題
費解的開關
你玩過“拉燈”遊戲嗎? 25 盞燈排成一個 5×5 的方形。 每一個燈都有一個開關,遊戲者可以改變它的狀態。 每一步,遊戲者可以改變某一個燈的狀態。 遊戲者改變一個燈的狀態會產生連鎖反應:和這個燈上下左右相鄰的燈也要相應地改變其狀態。 我們用數字 1 表示一盞開著的燈,用數字 0 表示關著的燈。 下面這種狀態 10111 01101 10111 10000 11011 在改變了最左上角的燈的狀態後將變成: 01111 11101 10111 10000 11011 再改變它正中間的燈後狀態將變成: 01111 11001 11001 10100 11011 給定一些遊戲的初始狀態,編寫程式判斷遊戲者是否可能在 6 步以內使所有的燈都變亮。 輸入格式 第一行輸入正整數 n,代表資料中共有 n 個待解決的遊戲初始狀態。 以下若干行資料分為 n 組,每組資料有 5 行,每行 5 個字元。 每組資料描述了一個遊戲的初始狀態。 各組資料間用一個空行分隔。 輸出格式 一共輸出 n 行資料,每行有一個小於等於 6 的整數,它表示對於輸入資料中對應的遊戲狀態最少需要幾步才能使所有燈變亮。 對於某一個遊戲初始狀態,若 6 步以內無法使所有燈變亮,則輸出 −1。 資料範圍 0<n≤500 輸入樣例: 3 00111 01011 10001 11010 11100 11101 11101 11110 11111 11111 01111 11111 11111 11111 11111 輸出樣例: 3 2 -1
題解
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; const int N=6; char g[N][N],backup[N][N]; int n; int dx[N]={-1,0,1,0,0},dy[N]={0,1,0,-1,0}; void turn(int x,int y){ for(int i=0;i<5;i++){ int a=dx[i]+x,b=dy[i]+y; if(a>=5||a<0||b>=5||b<0) continue; g[a][b]^=1; } } int main(){ cin>>n; while(n--){ for(int i=0;i<5;i++) cin>>g[i]; int res=10; for(int op=0;op<32;op++){ memcpy(backup,g,sizeof g); int stmp=0; for(int i=0;i<5;i++){ if(op>>i &1) { stmp++;; turn(0,i); } } for(int i=1;i<5;i++){ for(int j=0;j<5;j++){ if(g[i-1][j]=='0'){ stmp++; turn(i,j); } } } bool suf=true; for(int i=0;i<5;i++){ if(g[4][i]=='0'){ suf=false; break; } } if(suf) res=min(res,stmp); memcpy(g,backup,sizeof backup); } if(res>6) cout<<-1<<endl; else cout<<res<<endl; } return 0; }
這道題從暑假我寫了不下8遍,每次寫的第一次都寫不出來,現總結幾個問題,在列舉第一行開還是不開時,使用二進位制表示,0表示不開,1表示開,使用op右移i位與上1表示(op>>i&1)
在turn函式中,用g[x][y]^=1,表示取相反結果。