POJ2965解題報告(BFS,位壓縮)
阿新 • • 發佈:2019-02-04
因為和之前的翻轉問題十分類似,思想就不列舉了,貼上程式碼,供以後溫故:
#include <iostream> #include<fstream> #include<cstdlib> #include<cstring> #include<cstdio> #include<queue> #include<stack> using namespace std; const int MAX = 16; int final_step = MAX; const int MAX_STATE = 65536; int flips[4][4] = {4383, 8751, 17487, 34959, 4593, 8946, 17652, 35064, 7953, 12066, 20292, 36744, 61713, 61986, 62532, 63624}; struct POINT { int x; int y; }; POINT pts[MAX_STATE]; int states[MAX_STATE]; int steps[MAX_STATE]; int pres[MAX_STATE]; int qu[MAX_STATE]; int init(char str[]) { int current_state = 0; for(int i=0;i<MAX;i++){ if(str[i] == '+'){ current_state += (1 << i); } } return current_state; } int flip(int state,int x,int y) { state ^= flips[x][y]; return state; } void ans(int current_state) { memset(steps,0,sizeof(steps)); memset(states,0,sizeof(states)); memset(pres,0,sizeof(pres)); states[current_state] = 1; steps[current_state] = 0; pres[current_state] = 0; pts[current_state].x = -1; pts[current_state].y = -1; int front =0; int tail = 0; tail ++; qu[front] = current_state; int final_step = 0; while(true) { int cur = qu[front++]; if(cur == 0) { break; } for(int i=0;i<4;i++) { for(int j=0;j<4;j++) { int next = flip(cur,i,j); if(!states[next]) { states[next] = 1; steps[next] = steps[cur] + 1; pres[next] = cur; pts[next].x = i; pts[next].y = j; qu[tail++] = next; } } } } cout << steps[0] <<endl; stack<int> st; int tmp = 0; while(pres[tmp] != current_state) { st.push(tmp); tmp = pres[tmp]; } st.push(tmp); while(st.size()>0) { cout << pts[st.top()].x + 1 <<' ' << pts[st.top()].y + 1 <<endl; st.pop(); } } int main(int argc, char** argv) { //ifstream cin("L:/test.txt"); char str[MAX]; int number = 0; char c; while(cin >> c) { if(c==' ' || c == '\n') continue; str[number++] = c; if(number == 16) break; } int current_state = init(str); ans(current_state); //system("pause"); return 0; }
主要的點在於翻轉控制,畢竟BFS太簡單了,而且用queue的時候會有問題,自己定義佇列最好!
對於位壓縮的這些常量值,整理了一下思路,寫出了下面的程式碼,可以對照,在表中出現的值,和相應的執行程式碼:
binary 把每個數字對應在原圖中對應的位置標識了出來,非常直觀!/** * 位分佈圖(每一位對應於原題中該位置) * 0 1 2 3 * 4 5 6 7 * 8 9 10 11 * 12 13 14 15 */ #include<iostream> #include<cstdlib> #include<vector> using namespace std; const int row[] = {0xF,0XF0,0XF00,0XF000}; void binary(int num) { vector<int> v; int yu = num % 2; while(num / 2) { yu = num % 2; v.push_back(yu); num = num / 2; } v.push_back(1); while(v.size() <16) { v.push_back(0); } for(int i=1;i<=16;i++) { cout << v[i-1]; if(i % 4 == 0) cout <<endl; } cout <<endl; } int main() { int state = 0; int count = -1; for(int i=0;i<4;i++) { for(int j=0;j<4;j++) { count ++; state = 0; state ^= row[i]; state ^= (1 <<count);//行列交匯處異或之後復原了,要補上這一步!!! switch(j) { case 0: state ^= ((1<<0) + (1<<4) + (1<<8) +( 1<< 12)); break; case 1: state ^= ((1<<1) + (1<<5) + (1<<9) + ( 1<< 13)); break; case 2: state ^= ((1<<2) + (1<<6) + (1<<10) +( 1<< 14)); break; case 3: state ^= ((1<<3) + (1<<7) + (1<<11) +( 1<< 15)); break; } cout << count <<" : " <<state <<endl; binary(state); } } // system("pause"); return 0; }