深度优先搜索和广度优先搜索。
深度优先搜索
以输出排列数为例,主要进行状态的转移。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| #include<bits/stdc++.h> using namespace std; const int N =10; int path[N]; vector<bool>vis(N); int n; void dfs(int u) { if(u==n) { for(int i=0;i<n;i++)cout<<path[i]<<" "; cout<<endl; } else { for(int i=1;i<=n;i++) { if(!vis[i]) { path[u] = i; vis[i] = true; dfs(u+1); vis[i] = false; } } } } int main(void) { cin>>n; dfs(0); }
|
dfs也常用来进行暴力搜索,再数据量较小的情况下,对所有情况取值进行枚举进行搜索,通常根据题目情况配合回溯剪枝减小题目复杂度。
例题:
https://leetcode.cn/problems/partition-to-k-equal-sum-subsets/
https://leetcode.cn/problems/find-minimum-time-to-finish-all-jobs/
https://leetcode.cn/problems/matchsticks-to-square/
该三道题的代码思路大致相同,都是均分后,暴搜看能否搜索到正好满足的情况。
常用剪枝。
在搜索前进行情况判断,若已经不满足则不再进行后续搜索。
若回溯后,该组为值为0,后续无论如何搜索也不能得到有意义的答案,直接返回,不进行后续搜索。
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| class Solution { public: vector<int>sum; int k; vector<int>jobs; int ans; void dfs(int idx) { if(idx==jobs.size()) { int mx =0; for(int i=0;i<k;i++) { mx =max(mx,sum[i]); } ans =min(ans,mx); return ; } for(int i=0;i<k;i++) { sum[i]+=jobs[idx]; if(sum[i]<ans) { dfs(idx+1); } sum[i]-=jobs[idx]; if(sum[i]==0) { return; } } } int minimumTimeRequired(vector<int>& jobs, int k) { vector<int>sum(12,0); this->sum = sum; this->k = k; sort(jobs.begin(),jobs.end()); this->jobs =jobs; ans =1e9; dfs(0); return ans; } };
|
n-皇后问题
https://www.acwing.com/activity/content/problem/content/906/
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
| #include<bits/stdc++.h> using namespace std; const int N =20; bool col[N],dg[N],udg[N]; int n; char g[N][N]; void dfs(int u) { if(u==n) { for(int i=0;i<n;i++) { for(int j=0;j<n;j++) { cout<<g[i][j]; } cout<<endl; } cout<<endl; } for(int i=0;i<n;i++) { if(!col[i] && !dg[u+i] && !udg[n-u+i]) { g[u][i] = 'Q'; col[i] =true; dg[u+i] = true; udg[n-u+i] = true; dfs(u+1); col[i] =false; dg[u+i] = false; udg[n-u+i] = false; g[u][i]='.'; } } } int main(void) { cin>>n; for(int i=0;i<n;i++) { for(int j=0;j<n;j++) { g[i][j]='.'; } } dfs(0); }
|
在搜索路径时,应注意剪纸枝来提算法效率,有时需要多次剪枝。
例:https://leetcode-cn.com/problems/check-if-there-is-a-valid-parentheses-string-path/
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82
| class Solution { public: int m,n,c; bool flag; bool vis[101][101][201]; bool dfs(vector<vector<char>>& grid,int x,int y) { if (c > m - x + n - y - 1) return false; if(x==m-1 && y==n-1 && c==0) { flag =true; return true; } if(vis[x][y][c]) return false; vis[x][y][c]=1; if((x+1)<m && !flag) { if(grid[x+1][y]=='(' && !flag) { ++c; if(c>=0) { dfs(grid,x+1,y); } --c; } else if(grid[x+1][y]==')' && !flag) { --c; if(c>=0) { dfs(grid,x+1,y); } ++c; } } if((y+1)<n && !flag) { if(grid[x][y+1]=='(' && !flag) { ++c; if(c>=0) { dfs(grid,x,y+1); } --c; } else if(grid[x][y+1]==')' && !flag) { --c; if(c>=0 && !flag) { dfs(grid,x,y+1); } ++c; } } return false; } bool hasValidPath(vector<vector<char>>& grid) { flag =false; m=grid.size(); n=grid[0].size(); if(grid[0][0]==')' || grid[m-1][n-1]=='(' || (m+n)%2==0) { return false; } memset(vis,0,sizeof(vis)); c=1; dfs(grid,0,0); if(flag) { return true; } else { return false; } } };
|
广度优先搜索
广度优先搜索一般都借助队列这一数据结构,有一些固定的模式。
走迷宫。
https://www.acwing.com/activity/content/problem/content/907/
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| #include<bits/stdc++.h> using namespace std; const int N =105; int a[N][N]; int dis[N][N];
int dx[4] = {0,0,1,-1}; int dy[4] = {1,-1,0,0}; int main(void) { int n,m; cin>>n>>m; for(int i=0;i<n;i++) { for(int j=0;j<m;j++) { cin>>a[i][j]; } } queue<pair<int,int>>q; q.push({0,0}); memset(dis,-1,sizeof(dis)); while(!q.empty()) { auto [x,y] = q.front(); q.pop(); for(int i=0;i<4;i++) { int nx =x+dx[i]; int ny =y+dy[i]; if(nx>=0 && nx<n&&ny>=0 && ny<m && a[nx][ny]==0 && dis[nx][ny]==-1) { q.push({nx,ny}); dis[nx][ny] = dis[x][y]+1; } } } cout<<dis[n-1][m-1]+1; }
|
八数码
https://www.acwing.com/problem/content/847/
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
| #include<bits/stdc++.h> using namespace std; unordered_map<string,int>d; queue<string>q; int dx[4]={0,0,1,-1}; int dy[4]={1,-1,0,0}; int bfs(string start) { q.push(start); d[start]=0; string endstate = "12345678x"; while(!q.empty()) { string t= q.front(); q.pop(); int dis =d[t]; if(t==endstate) { return dis; } int k = t.find('x'); int x = k/3; int y = k%3; for(int i=0;i<4;i++) { int nx = x+dx[i]; int ny = y+dy[i]; if(nx>=0 && nx<3 && ny>=0 && ny<3) { swap(t[k],t[3*nx+ny]); if(!d.count(t)) { d[t] =dis+1; q.push(t); } swap(t[3*nx+ny],t[k]); } } } return -1; } int main(void) { string start; for(int i=0;i<9;i++) { char c; cin>>c; start+=c; } cout<<bfs(start)<<endl; }
|