搜索
深度优先搜索DFS
尽可能往深搜,到头回溯接着进行搜索(一条路走到黑,不撞南墙不回头);
空间: O(h) 与深度成正比
着重考虑顺序(遍历题目的所有方案);触底回头的过程叫回溯 ;回溯的时候一定要恢复现场 , 还原状态 ;进入递归就修改状态,递归结束后进行恢复 ;
剪枝:提前判断当前的方案一定是不合法的,直接回溯。
n皇后问题的对角线
看一下看一下 我们可以对nn正方形进行一个枚举 (0,0) (0,1) (0,2) (0,3) (0,4) (1,0) (1,1) (1,2) (1,3) (1,4) (2,0) (2,1) (2,2) (2,3) (2,4) (3,0) (3,1) (3,2) (3,3) (3,4) (4,0) (4,1) (4,2) (4,3) (4,4) 这是,坐标,可以理解为一个是x,一个是y,也可以理解为题目中的u和i 仔细观察,每条从右上到左下的对角线,他们横纵坐标相加的值都是相等的,对比下面图看一下 (0) (1) (2) (3) (4) (1) (2) (3) (4) (5) (2) (3) (4) (5) (6) (3) (4) (5) (6) (7) (4) (5) (6) (7) (8) *这就是u + i 为 副对角线,因为这条对角线上的点都可以通过u + i,也就是横纵坐标来找到这个dg[u + i]; 同样的,u - i + n 的值我也列出来 (5) (4) (3) (2) (1) (6) (5) (4) (3) (2) (7) (6) (5) (4) (3) (8) (7) (6) (5) (4) (9) (8) (7) (6) (5) 看看,从左上角到右下角的这些主对角线,是不是横纵坐标相加都等于一个值 那么到此,这边对角线问题就解决了,是不是很好理解呢-v-
不具有最短路的特性;
广度优先搜索BFS
眼观六路耳听八方,一层一层搜索,搜完一层再往下搜(宽度优先);
空间: O(2^h)与深度成指数关系
可以搜到的是最短路径,因为是一圈一圈的往下进行搜索(每次拓展到距离为一的所有点);
具有最短路的特性;
模板:
#include <bits/stdc++.h> using namespace std; const int N = 110; int n , m ; int a[N][N]; int dis[N][N]; typedef pair<int,int> PII; int dx[4] = {1,-1,0,0}; int dy[4] = {0,0,1,-1}; void bfs() { queue<PII> q; memset(dis , -1, sizeof (dis)); dis[0][0] = 0; q.push({0,0}); while(!q.empty())//队列不为空时 { int x = q.front().first , y = q.front().second;//取出队列首元素 q.pop();//弹出队列首元素 for(int i = 0 ; i < 4 ; i ++)//尝试四个移动方向 { int xx = x + dx[i] , yy = y + dy[i]; if(xx >= 0 && xx < n && yy >= 0 && yy < m && a[xx][yy] == 0&& dis[xx][yy] == -1) { dis[xx][yy] = dis[x][y] + 1;//距离加一 q.push({xx,yy});//将新移动到的位置推入队列当中去 } } } } int main() { cin >> n >> m; for(int i = 0 ; i < n ; i ++) { for(int j = 0 ; j < m ; j ++) { cin >> a[i][j]; } } bfs(); return 0; }
树和图的存储
tips : 树是一种特殊的图(无环连通图);无向图是一种特殊的有向边 (双向图)
邻接矩阵
a ——>b 则可以记为g[a] [b] = 权重; 但是无法存储无向图 且空间复杂度较为高;邻接矩阵无法存储重边,较适合建立稠密图
邻接表
每个点上都创建一个单链表来存储该点能通向哪些点;
添加一条新的边 , 直接在头节点处插入 :
图的遍历
深度优先搜索和广度优先搜索的点一般只遍历一遍。 深度优先遍历能够算出每一个子树的大小