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.复杂版走迷宫,中间有些不能走,四个方向都可以走。
参考链接:https://blog.csdn.net/qq_37703898/article/details/78445787
多少种? 动态规划,对于不能走的地方直接置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.复杂版 走迷宫,中间有些不能走,四个方向都可以走,求是否存在一条唯一的路径,达到终点。
这个可以利用回溯法,用一个矩阵来记录当前这个点是否可达。