問題描述:






程序代碼:
/* *思路1:枚舉所有可能的開關狀態,對每個狀態計算下最后燈的情況,看是否都熄滅 * 每種按鈕有兩種狀態,一共有30個開關,那么狀態數是2的30次方,太多不可取 *思路2:如何減少枚舉的數目呢? 如果存在某個局部,一旦這個局部狀態被確定后,那么剩余其他部分的狀態只能 是確定的一種或者不多的n種,那么只需要枚舉這個局部狀態即可 */#include <memory>#include <string>#include <cstring>#include <iostream>using namespace std;/* *因為開關的狀態只有0和1,并且每一行有六位,所以可以用一個char類型的字符來表示每一行的狀態 *所以所有的狀態可以用一個一維的字符數組來表示,通過對字符進行位運算來操作 */char oriLights[5];//存儲初始燈的狀態char lights[5];//存儲變化中燈的狀態char result[5];//存儲燈的結果狀態int GetBit(char c,int i)//獲取字符c的第i位{ return (c>>i)&1;}void SetBit(char & c,int i,int v)//把字符c的第i為設置為v{ if(v) { c =c | (1<<i);//如果v為1,則把1左移i位,然后與c進行或運算 } else c =c & ~(1<<i);//如果v為0,則把把1左移i位取反,與c進行與運算}void FlipBit(char &c,int i){ c ^=(1<<i);//一個數和1異或就會被反轉,和0異或不變}void OutputResult(int t,char result[]){ cout << "PUZZLE #" <<t<<endl; for(int i=0;i<5;i++) { for( int j=0;j<6 ;j++) { cout<<GetBit(result[i],j); if(j<5) cout<< " "; } cout<<endl; }}int main(){ int T;//有T組測試數據 cin>>T; for(int t=1 ;t<=T; ++t) { for(int i=0;i<5;++i) for(int j = 0;j<6 ;++j) { int s;//s代表數據第i行第j列的數據,0或1 cin>>s; SetBit(oriLights[i],j,s); } //開始枚舉第一行的所有狀態 for(int n = 0; n<64;++n) { int switchs = n;//switchs 表示每一次循環第一行的狀態 memcpy(lights,oriLights,sizeof(oriLights));//第一行的狀體變化一次,就把初始狀態賦給lights for(int i=0; i< 5 ; ++i) {//開始枚舉在第一行已經確定的一種狀態下,枚舉所有行的狀態 result[i] = switchs;//把第一行的狀態保存到結果狀態中 for(int j = 0;j< 6 ;++j) {//枚舉每一行的每一列的狀態 if(GetBit(switchs,j))//如果第i行第j列為1的話,表示燈亮,進行反轉 { if(j>0) FlipBit(lights[i],j-1); FlipBit(lights[i],j); if(j<5) FlipBit(lights[i],j+1); } } if( i < 5)//開始處理i+1行的燈 { lights[i+1] ^= switchs;//異或運算 } switchs = lights[i];//把下一行的狀態賦給switchs } if(lights[4]==0) { OutputResult(t,result); break; } } } return 0;}結果已經在POJ上面運行通過
新聞熱點
疑難解答