關於走格子的問題
阿新 • • 發佈:2018-12-10
dfs: 所有可能的路徑,是否存在某一條路徑
bfs: 遍歷圖,最短路徑
1.簡單版:從(0,0)走到(n,m),只能往下或往右走,最短的路徑。(這裡最短路徑的意思就是隻會走m+n個空格)注意這裡的矩陣大小是(m+1)*(n+1)
多少種走法:C(m+n,n),或者用動態規劃的方式求解。
記錄路徑:用dfs
typedef pair<int,int> v; int m, n; int cnt = 0; #define M 100 #define N 100 int dx[2]={1,0}; int dy[2]={0,1}; bool vis[M][N]; void print(vector<v> res){ for(int i =0 ; i < res.size(); i++){ cout<<"("<<res[i].first<< ","<< res[i].second<<")"; } cout<<endl; } void dfs(vector<v> res, int x, int y){ if(x <0 || x>= m || y <0 || y >=n) return; if(vis[x][y] == true) return; if( x == m-1 && y == n-1){ print(res); cnt++; return; } vis[x][y] = true; res.push_back(v(x,y)); dfs(res,x+1,y); dfs(res,x,y+1); vis[x][y] = false; } int main(){ cin >> m >> n; memset(vis,false,sizeof(vis)); vector<v> res; dfs(res,0,0); cout<< "total:"<< cnt<<endl; }
PS進階:在如下8*6的矩陣中,請計算從A移動到B一共有多少走法?要求每次只能向上或向右移動一格,並且不能經過P。
首先從A到B總共有c(7+5,5)種走法,從A到P有c(3+3,3)種走法,從P到B有c(4+2,2)種走法。
所以不經過點P得走法共有c(12,5)-(c(6,3)*c(6,2))種,即492種,
2. 走迷宮,可以走兩個方向。
3.複雜版走迷宮,中間有些不能走,四個方向都可以走。
多少種? 動態規劃,對於不能走的地方直接置0。
記錄所有路徑:dfs
輸出最短路徑的長度
typedef pair<int,int> v; queue<v> q; #define N 3 #define M 3 char a[M][N]; int b[M][N]; bool vis[M][N]; int dx[4] = {-1,1,0,0}; int dy[4]= {0,0,1,-1}; int bfs(int m, int n){ q.push(v(m,n)); b[m][n] = 0; while(!q.empty()){ v cur = q.front(); q.pop(); if(cur.first == M && cur.second == N){ break; } for(int i =0 ; i < 4; i++){ int x = cur.first + dx[i]; int y = cur.second + dy[i]; if(x >=0 && x < M && y >=0 && y < N && a[x][y] != '#' && vis[x][y] != true){ // b[][]記錄的是該座標上的路徑長度;如果是記錄路徑,則儲存的是上一個路徑座標。具體見下一段程式碼 b[x][y] = b[cur.first][cur.second] +1; q.push(v(x,y)); vis[x][y] = true; } } } return b[M-1][N-1]; } int main(){ for(int i = 0 ; i < N; i++){ for(int j = 0; j < N; j++){ cin>> a[i][j]; } } cout<< bfs(0,0); }
記錄最短路徑:
- 利用bfs走迷宮,建立兩個陣列vis[][]和b[][],一個記錄當前點是否訪問過,另一個記錄當前訪問點的前一個點是哪個;然後回溯最短路徑的點。只要搜尋一次,第一次搜尋到的結果就是最短的
typedef pair<int,int> v; queue<v> q; #define N 3 #define M 3 char a[M][N]; v b[M][N]; bool vis[M][N]; int dx[4] = {-1,1,0,0}; int dy[4]= {0,0,1,-1}; void bfs(int m, int n){ q.push(v(m,n)); b[m][n] = v(m,n); while(!q.empty()){ v cur = q.front(); q.pop(); if(cur.first == M && cur.second == N){ break; } for(int i =0 ; i < 4; i++){ int x = cur.first + dx[i]; int y = cur.second + dy[i]; if(x >=0 && x < M && y >=0 && y < N && a[x][y] != '#' && vis[x][y] != true){ b[x][y] = cur; cout<< x<<y<<"("<<cur.first << "," << cur.second << ")" << endl; q.push(v(x,y)); vis[x][y] = true; } } } } int main(){ for(int i = 0 ; i < N; i++){ for(int j = 0; j < N; j++){ cin>> a[i][j]; } } bfs(0,0); int x = M-1, y =N-1; stack<v> s; while(1){ s.push(v(x,y)); if(x == 0 && y == 0) break; int mx = b[x][y].first; int my = b[x][y].second; x = mx; y = my; } while(!s.empty()){ cout<< "("<<s.top().first << "," << s.top().second << ")" ; s.pop(); } return 0; }
- 利用dfs,主要思想是通過回溯搜尋出所有的結果,然後比較得到最小的。但是這種方法比較耗時。
4.複雜版 走迷宮,中間有些不能走,四個方向都可以走,求是否存在一條唯一的路徑,達到終點。
這個可以利用回溯法,用一個矩陣來記錄當前這個點是否可達。