POJ1176 (规律循环)
问题:
有N个开着的灯,和控制这个N个灯的四个开关。四个开关作用不同。第一个开关:flip所有的灯。第二个开关:flip奇数编号的灯。第三个开关:flip偶数编号的灯。第四个开关:flip编号为3 * K + 1 的灯,其中K = 0,1,2....。已知在C次操作后其中几个灯的状态,给出所有灯在这C次操作后所有可能的状态。
方法:
通过观察可以发现,这些灯一共可以分成4种,同种灯无论在何种操作下,状态都是相同的。即:(1)编号为1,7,13,19....的灯。(2)编号为4,10,16,22....的灯。(3)编号为奇数,但是不属于(1)的灯。 (4)编号为偶数,但是不属于(2)的灯。
对于第(1)种灯,唯1,2,4号开关能够控制,且这些开关的作用是等效的。
对于第(2)种灯,唯有1,3号开关能够控制,且这些开关的作用是等效的。
对于第(3)种灯,唯有1,2号开关能够控制,且这些开关的作用是等效的。
对于第(4)种灯,唯有第1,3,4号开关能够控制,且这些开关的作用是等效的。
同一个开关无论按动多少次,其效果只有两种。即所有奇数次的按动的效果与按动一次相同;所有偶数次的按动与不按动的效果也相同。
现在只需将这四个开关的按动次数按奇偶枚举(共有2 * 2 * 2 * 2 = 16种情况),然后与已知的C次操作后的灯的状态对比即可,若符合,则为潜在的正确答案。这里说是“潜在”的答案,是因为还需要考虑该开关组合能否在C次操作内完成。不可能的情况共有2种:(1)按动奇数次的开关的个数大于C。(2)按动奇数次的开关的个数与C的奇偶性不同。排除这两种情况之后,便得到了正确答案。
附代码:
#include<iostream> #include<string> #include<vector> #include<algorithm> using namespace std; bool isEven(int x){ return (x % 2 == 0); } bool is3K1(int x){ return ((x - 1) % 3 == 0); } int main(){ int N, C; int isOn[4] = {0}; cin >> N >> C; vector<string> result;int temp; while(1){ cin >> temp; if(temp == -1) break; if(is3K1(temp) && isEven(temp)){ isOn[3] = 1; }else if(is3K1(temp) && ! isEven(temp)){ isOn[0] = 1; }else if(isEven(temp)){ isOn[1] = 1; }else{ isOn[2] = 1; } } while(1){ cin >> temp; if(temp == -1) break; if(is3K1(temp) && isEven(temp)){ isOn[3] = -1; }else if(is3K1(temp) && ! isEven(temp)){ isOn[0] = -1; }else if(isEven(temp)){ isOn[1] = -1; }else{ isOn[2] = -1; } } for(int i = 0; i < 16; i++){ string temp(N, '1'); bool on[4] = {0}; if((i & 1) == 0) on[0] = 0; else on[0] = 1; if((i & 2) == 0) on[1] = 0; else on[1] = 1; if((i & 4) == 0) on[2] = 0; else on[2] = 1; if((i & 8) == 0) on[3] = 0; else on[3] = 1; if((on[0] + on[1] + on[3]) % 2 == 0){ if(isOn[0] == -1) continue; }else{ if(isOn[0] == 1) continue; } if((on[0] + on[2]) % 2 == 0){ if(isOn[1] == -1) continue; }else{ if(isOn[1] == 1) continue; } if((on[0] + on[1] ) % 2 == 0){ if(isOn[2] == -1) continue; }else{ if(isOn[2] == 1) continue; } if((on[0] + on[2] + on[3]) % 2 == 0){ if(isOn[3] == -1) continue; }else{ if(isOn[3] == 1) continue; } if((on[0] + on[1] + on[2] + on[3]) % 2 != C % 2) continue; if((on[0] + on[1] + on[2] + on[3]) > C) continue; if(on[0] == 1){ for(int i = 0; i < temp.size(); i++) if(temp[i] == '0') temp[i] = '1'; else temp[i] = '0'; } if(on[1] == 1){ for(int i = 0; i < temp.size(); i += 2){ if(temp[i] == '0') temp[i] = '1'; else temp[i] = '0'; } } if(on[2] == 1){ for(int i = 1; i < temp.size(); i += 2){ if(temp[i] == '0') temp[i] = '1'; else temp[i] = '0'; } } if(on[3] == 1){ for(int i = 0; i < temp.size(); i += 3) if(temp[i] == '0') temp[i] = '1'; else temp[i] = '0'; } result.push_back(temp); } sort(result.begin(), result.end()); for(int i = 0; i < result.size(); i++) cout << result[i] << endl;; }