廣度優先搜尋——經典的8數碼問題
阿新 • • 發佈:2019-02-15
話不多說,直接貼程式碼吧~
//廣度搜索-8數碼問題 #include <iostream> #include <cstring> using namespace std; const int Max = 8; const int All = 363000; //總的個數有9!= 362880,故取363000 int Fac[Max] = {1}; //康託展開需要用到的工具 char a[All][9]; bool visit[All]; char goal[9]; int dis[All]; int dir[4][2]={{-1,0},{1,0},{0,1},{0,-1}}; //搜尋時用到的四個方向 void Init(); //輸入,以及初始化Fac int getValue(char* s); //康託展開來Hash化局面!!! bool check(int head); //check是否已經到達目的狀態 int bfs(); //所有是搜尋過程! int main() { Init(); int ans = bfs(); if(ans == -1) cout << "No answers!" << endl; else cout << ans << endl; return 0; } void Init() { for(int i=0; i<9; ++i) cin >> a[0][i]; for(int i=0; i<9; ++i) cin >> goal[i]; for(int i=1; i<Max; ++i) Fac[i] = Fac[i-1] * i; } int getValue(char* s) { int sum = 0, cnt, key = 1; for(int i=0; i<9; ++i) { cnt = 0; for(int j=i+1; j<9; ++j) if(s[j] < s[i]) ++cnt; sum += cnt * Fac[Max-i]; } return sum; } inline bool check(int head) { for(int i=0; i<9; ++i){ if(a[head][i] != goal[i]) return false; } return true; } int bfs(){ int head = 0, tail = 1; int x, y, z, nx, ny, nz; while(head < tail){ if(check(head)) return dis[head]; for(int i=0; i<9; ++i){ if(a[head][i] == '0'){ x = i / 3; y = i % 3; z = i; break; } } for(int i=0; i<4; ++i){ nx = x + dir[i][0]; ny = y + dir[i][1]; nz = 3*nx + ny; if(nx<0 || ny<0 || nx>2 || ny>2) continue; for(int i=0; i<9; ++i) a[tail][i] = a[head][i]; a[tail][z] = a[tail][nz]; a[tail][nz] = '0'; int t = getValue(a[tail]); if(!visit[t]){ visit[t] = true; dis[tail] = dis[head] + 1; ++tail; } } ++head; } }
今天剛學了“寬搜”,見識到了神奇的“康託展開”的hash化的方式,也懂得了“康託逆展開”的方法,明天我會把這兩個的程式碼也放上來!
寬搜的精髓,個人覺得在於兩個點——
1. 如何如何構造搜尋樹
2. 如何判斷局面重複
只要做好這兩個點,其他的,水到渠成!!!加油,明天繼續做多點“寬搜”題目,為了明天下午的ccf認證!!!