搜索

  • 前言
  • 深度优先搜素
    • 如何搜索
  • 迭代加深
    • 加成序列
    • 导弹防御系统
  • BFS 变形
    • 双端队列BFS
    • 优先队列BFS
    • 双向BFS
    • 噩梦
    • 字串变换

前言

人人都说搜素搜素有手就行,我听起来啥感觉自己没手呢!
在看这个前言之前,读者应该学过基本的算法和数据结构了。
通过这个题目来进行讲解生日蛋糕 下边附有代码:

有一篇文章将,领悟了二叉树的前、中和后序遍历后你就能理解搜索这个东西了。那么我们就依据这个来进行讨论一下。 在搜索的时候我们知道,搜索的状态 搜索树就是一颗多叉树 , 当前节点的所有决策就是该节点节点的孩子。 因为二叉树只有左右两个孩子。 下面这个dfs 其实就是前序遍历的变形。 二叉树的前序遍历是这样:

void dfs( BiTree T){if(T){vist(T);
if(T->lchild) dfs(T->lchild);
if(T->rchild) dfs(T->child);
}
}// 可能感觉不太想,不过我们修改一下。
void dfs( BiTree T){if(T){vist(T);
for(int i = 0 ; i < 2 ; ++i){if(i == 0 && T->lchild) dfs(T->lchild);if(i ==1 && T->rchild) dfs(T->rchild); }
}
}

之所以我们不写成下面的形式是因为,1是二叉树的下一个状态是已知的。2是二叉树直接通过左右孩子dfs即可,不用通过遍历来引出状态。3是同一个节点访问的结果是一样的所有访问一次就好。

还有一个问题是什么时候需要恢复现场什么时候不用呢?
好比下边这个代码我们在dfs结束后不需要恢复现场,而且也没有必要恢复现场。我们的的每一个路径上的节点都是相互独立的。 而有些题目需要就好比八皇后或者图的最短路径等。我们在遍历的时候以这个节点开始去遍历的点,我们通过别的节点也能到达,那么如果我们不恢复,那么别人就无法访问了。
判断是否DFS是否需要恢复现场
代码:

#include<iostream>
#include<algorithm>
#include<cmath>using namespace std;const int N = 25 , INF  = 1e9;int n, m ;
int minv[N] , mins[N];
int H[N] , R[N] ;
int ans = INF;void dfs(int dep , int v , int s){if (v + minv[dep] > n) return;if (s + mins[dep] >= ans) return;if (s + 2 * (n - v) / R[dep + 1] >= ans) return;if (!dep){if (v == n) ans = s;return;}for (int r = min(R[dep + 1] - 1, (int)sqrt(n - v)); r >= dep; r -- )for (int h = min(H[dep + 1] - 1, (n - v) / r / r); h >= dep; h -- ){int t = 0;if (dep == m) t = r * r;R[dep] = r, H[dep] = h;dfs(dep - 1, v + r * r * h, s + 2 * r * h + t);}}int main(){cin>> n >> m;for(int i = 1 ; i <= m ; ++i){minv[i] = minv[i-1] + i * i * i;mins[i] = mins[i - 1] + 2 * i  * i;}H[m+1] = R[m+1] = INF;dfs(m , 0 , 0);if(ans == INF)cout<<0 <<endl;elsecout<<ans<<endl;return 0;
}

深度优先搜素

如何搜索

这是最重要的一步,也就是说我们要以什么样的顺序搜索才能不重不漏的将每一个情况都能枚举到。只有先做到这一步才能想着如何剪枝等优化技巧。
下面以一道题来进行说明。

虫食算

题目大意:
题目是让我们对每一个字母进行赋值,使得符合该加法等式。

解题思路:

就是爆搜。重点是如何进行搜索,即如何对每一个字母进行赋值所有的情况。首先第一点我们可以规定一个搜索顺序,我们可以对字母进行编号,而编号的话我们可以按照从右往左依次对字母进行编号。而因为我们这样编号的话那么是不符合字母表顺序的因此我们可以用一个数组q来存下这个映射关系。然后我们从第一个字母开始进行遍历 , 在每一次中字母有 n 种选择,在这n种中选出没有被挑选的。

代码:

#include<iostream>
#include<algorithm>
#include<cstring>using namespace std;const int N = 30;
char g[N][N];
int st[N] , path[N] , q[N];
int n ; bool check(){// 遍历每一列for(int i = n - 1 , t = 0; ~i ; --i){int a = g[0][i] - 'A' , b = g[1][i] - 'A' , c = g[2][i] - 'A'; // 获取字母在序列中的位置if(path[a] != - 1 && path[b] != -1 && path[c] != -1){a= path[a] , b = path[b] , c = path[c];if(t != -1){ // 前一列是确定的了if((a + b + t) % n != c)return false;if(!i && a + b >= n)return false; // 最高位t = (a + b + t) / n; // 当t 确定了 那么这个t的进位再能确定}else{if( (a + b ) % n != c && (a + b + 1) % n != c)return false;if(!i && a + b  >= n)return false;}}else t = - 1 ;}return true;
}// 这个u 第几个字母,所以是依次对字母进行赋值
bool dfs(int u )
{if(u == n )return true;//没一个path 位置遍历 n 中 可能 , 那每一个为值为一个字母的值// 所以就相当于对每一个字母符 n 个值for(int i = 0 ; i < n ; ++i){if(!st[i]){st[i] = true;path[q[u]] = i; // 找到u 位置if(check() && dfs(u + 1))return true;st[i] = false;path[q[u]] = -1;}}return false;
}
int main(){scanf("%d",&n);for(int i = 0 ; i < 3 ; ++i)scanf("%s",g[i]);for(int i = n - 1 , k = 0 ; ~i ; -- i)for(int j = 0 ; j < 3 ; ++j){int x = g[j][i] - 'A';if(!st[x]){st[x] = true;q[k++] = x;}}memset(path , -1 , sizeof path);memset(st , 0 , sizeof st);dfs(0);for(int i = 0 ; i < n ; ++i)cout<<path[i] << " ";return 0;
}

迭代加深

加成序列

这个迭代深度就有点想 ,答案解的长度。

加成序列

解题思路:

看到最短的一个解,首先想到的应该都是BFS不过这题不好用BFS , 因此我们可以采用DFS中的迭代加深的方法。 其中迭代深度就是求解序列的长度。在没一次dfs中我们的状态是 当前要填的空,和序列的长度。 搜索结束是当 填的空已经为序列长度了就返回 , 当序列最后一个为n时(条件)返回true ,否则返回false 。 当前这个空 由条件 知 我们可选的集合 会前边 数两两想加的和 。同时这个和我们要满足比前一个大 , 同时不能大于n 。 在这里我们可以利用一个bool 数组来进行剪枝 , 避免对 和 一样的进行搜索。

代码:

#include<iostream>
#include<algorithm>
#include<queue>
using namespace std;const int N = 110;int n ;
int path[N];bool dfs(int u, int depth){if(u == depth) return path[u-1] == n;bool st[N] = {false};for(int i = u - 1 ; i >=0 ; --i)for(int j = i ; j >= 0 ; --j){int s = path[i] + path[j];if(s > path[u-1] && s <= n  && !st[s]){st[s] = true;path[u] = s;if(dfs(u+1 , depth)) return true;}}return false;
}int main(){while(cin>> n , n){int depth = 1;path[0] = 1 ;while(!dfs(1 , depth)) depth++;for(int i = 0 ; i < depth ; ++i)cout<<path[i]<< " ";cout<<endl;}return 0;
}

导弹防御系统

  • 小知识:对于DFS来求最短的问题我们一般有两个思路 , 一个是定义一个全局变量然后更新,二就是迭代加深

导弹防御系统
解题思路:

我们的搜索顺序就是依次遍历每一个数字的情况,而每一个数字都有两种选择,一个是上升,一个是下降。不过在两个序列中又有很多个上升或者下降序列。这会导致我们搜索空间太大,不过我们由一个性质类似单调队列的思路,我们在选上升序列的时候选择第一个小于的就好,因为当这个数x加入后有一个序列的下一个数一定是x结尾这个是固定的了,不过其余序列的结尾是变得,我们要想达到最优的情况,那么选择一个里其最近的一个小于它的是最优的。下降序列同理。

关键点:

  1. 对于加入别的序列我们要记录下原先的数,方便回溯。

代码:


```cpp
#include<iostream>
#include<algorithm>using namespace  std;const int N = 51;int n ;
int h[N] , up[N] , down[N];bool dfs(int depth , int u , int su , int sd){if(su + sd > depth )return false;if(u == n)return true;bool flag = false;for(int i = 0; i < su ; ++i){if(up[i] < h[u]){int t = up[i];up[i] = h[u];if(dfs(depth , u + 1 , su , sd))return true;up[i] = t;flag = true;break;}}if(!flag){up[su] = h[u];if(dfs(depth , u + 1 , su + 1 , sd))return true;}flag = false;for(int i = 0; i < sd ; ++i){if(down[i] > h[u]){int t = down[i];down[i] = h[u];if(dfs(depth , u + 1 , su , sd))return true;down[i] = t;flag = true;break;}}if(!flag){down[sd] = h[u]; // 从0开始存if(dfs(depth , u + 1 , su , sd + 1))return true;}return false;
}int main(){while(cin>>n , n){for(int i = 0 ; i < n ; ++i)scanf("%d",&h[i]);int depth = 1 ;while(!dfs(depth , 0 , 0 , 0))depth++;cout<<depth<<endl;}return 0;
}
# 深度搜索(BFS)## 权值相同的多源最短路问题
[矩阵距离](https://www.acwing.com/problem/content/175/)问题描述:
>问题是让我们求出 , 每个数字到最近的1的曼哈顿距离。解题思路:
> 该题可以转化为最短路问题 , 只不过边的权重都为1 。 边指的是相邻点才连边。由于边权都相同,那么我们就可以用BFS来求出最短路,这个就相当于一个简化版的dijkstra算法,队头一定是最小的节点。 由于这题是一个多源最短路问题,我们不可能遍历每一个节点。这题的巧妙之处是利用宽搜的性质,先将距离为0的点放入队列中 ,然后依次拓展, 那么我们就可以在O(n)的时间内解出。关键问题:1. 如何记录距离:一般BFS我们都会用一个数组(dist)来存储距离 , 同时 这个数组还可以用来记录这个节点是否被访问过。代码:```cpp
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<queue>
#include<cstring>using namespace std;typedef pair<int , int >PII;const int N  = 1000;
int g[N][N] , n , m;
int dist[N][N];queue<PII>q;void bfs(){int dx[4] = { 1, -1 , 0 , 0 } , dy[4] = { 0,0,1,-1};while(q.size()){auto t = q.front();q.pop();for(int i = 0 ; i < 4 ; ++i){int x = t.first + dx[i] , y = t.second + dy[i];if(x < 0 || x >= n || y >= m ||y < 0)continue;if(dist[x][y] == -1){dist[x][y] = dist[t.first][t.second] + 1;q.push({x,y});}}}}int main(){memset(dist , -1 , sizeof(dist));cin>>n>>m;getchar();for(int i = 0 ; i < n; ++i){  for(int j = 0 ; j < m ; ++j){char ch;ch = getchar();g[i][j] = ch - '0';if(g[i][j] == 1)dist[i][j] = 0 , q.push({i , j});}getchar();}bfs();for(int i = 0 ;i < n ; ++i){for(int j = 0 ; j < m ; ++j)cout<<dist[i][j] <<" ";cout<<endl;}return 0;
}

BFS 变形

双端队列BFS

在最基本的广度优先搜索中,每次沿着分支的扩展都记为“一步”,我们通过逐层搜索,解决了求从起始状态到每 的最少步数的问题。这其实等价于在一张边视均为1的图上执行广度优先遍历,求出每个点相对于起点的最短距离(层次)。在第021节中我们曾讨论过这个问题,并得到了“队列中的状态的层数满足两段性和单调性”的结论。从而我们可以知道,每个状态在第一次被访问并入队时,计算出的步数即为所求
然而,如果图上的边权不全是1呢?换句话说,如果每次扩展都有各自不同的“代价“ , 我们相求出起始状态到每一个转态的最小代价? 下面通过一题来解决0和1的时候

电路维修




参考:出处

小技巧:

  1. memset 的时候 , 是有四个字节的。因此 0x3f 会变为 0x3f3f3f3f .

代码:

#include<stdio.h>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<deque>using namespace std;const int N = 501;
typedef pair<int ,int > PII;int n,m;
char g[N][N];
int d[N][N] ;int bfs(){memset(d, 0x3f , sizeof(d));deque<PII> dq;dq.push_back({0,0});d[0][0] = 0;int dx[4] = {-1 , -1 , 1,1} , dy[4] = {-1,1,1,-1 }; // 坐标的偏移量int ix[4] = {-1,-1,0,0} , iy[4] = {-1,0,0,-1}; // 找到该坐标对应的字符的位置char cs[] = "\\/\\/"; // 正确的字符位置while(dq.size()){auto t = dq.front();dq.pop_front();int x = t.first , y = t.second;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 ){int a = x + ix[i] , b = y + iy[i];int w = 0 ;if(g[a][b] != cs[i]) w = 1 ;if(d[xx][yy] > d[x][y] + w){d[xx][yy] = d[x][y] + w;if(w) dq.push_back({xx,yy});else dq.push_front({xx,yy});}}}}if(d[n][m] == 0x3f3f3f3f)return -1;else return d[n][m];}int main(){int t ;cin>>t;while(t--){cin>>n>>m;for(int i = 0 ; i < n ; ++i)scanf("%s",g[i]);int ans = bfs() ;if(ans == -1) cout<<"NO SOLUTION\n";else printf("%d\n",ans);}return 0;
}

优先队列BFS

相对于上一个问题,对于更加普遍的情况,也就是每次扩展的代价是不一样的,求出初始状态到每一个状态的最小代价。就相当在一张带权图上求出起点到每一个点的最短路。那么这种情况我们就可以进行广搜了。下面以一道题来举例。

装满的油箱

题目大意:
题目就是求出从开始城市到终点城市的最小花费。

解题思路:

和最短路不一样的是,这里油的数量是在变化的。 面对这种情况我们可以将城市与油量拆分成一个点对<城市,当前剩余油量> 通过这个点对来进行深搜。我们用一个二维数组dist[N][C]来记录最小花费。因此我们最终要求得急速dist[S][0] -- > dist[E][0] 的最小代价。为了方便建立优先队列,我们会以 代价也放入队列中,每次去出代价最少的进行扩展。对于每一个状态有两个可以进行转移的状态, 一 是 (如果加一升油没满)就加一升油 , 二、是遍历所有能去的城市。 因此我们需要建图。

代码:

#include<cstring>
#include<iostream>
#include<queue>
#include<algorithm>
#include<stdio.h>using namespace std;const int N = 1010, C = 110, M = 20010;struct ver{int d , u , c;bool operator < (const ver & a)const{return d > a.d;}
};int h[N] , E[M] , W[M] , ne[M] , tot;
int price[N] ;
bool st[N][C];
int dist[N][C];
int n, m ;void add(int u , int v ,int w){E[tot] = v  , W[tot] = w , ne[tot] = h[u] , h[u] = tot++; }int bfs(int s , int e, int cab){priority_queue<ver> heap;heap.push({0 , s , 0});memset(dist , 0x3f , sizeof dist);memset(st , false , sizeof st);dist[s][0] = 0;while(heap.size()){auto t = heap.top();heap.pop();if(t.u == e) return t.d; // 到达终点城市if(st[t.u][t.c])continue; // 访问过了 , 避免重复访问st[t.u][t.c] = true;// 加一升油if(t.c < cab){if(dist[t.u][t.c + 1 ] > t.d + price[t.u]){dist[t.u][t.c + 1] = t.d + price[t.u];heap.push({dist[t.u][t.c + 1] , t.u , t.c + 1});}}// 遍历能走的边for(int i = h[t.u] ; ~i ; i = ne[i]){int y = E[i];if(t.c >= W[i]){ // 剩余的油能走这条边if(dist[y][t.c - W[i]] > t.d){dist[y][t.c - W[i]] = t.d;heap.push({dist[y][t.c - W[i]] , y , t.c - W[i]});}} }}return -1;
}int main(){memset(h , -1 , sizeof h);scanf("%d%d", &n , &m);for(int i = 0 ; i < n ;++i )scanf("%d", &price[i]);for(int i = 0 ; i  < m ;++i){int u , v, w;scanf("%d%d%d",&u, & v, & w);add(u,v,w) , add(v,u,w);}int query;scanf("%d" ,&query);while(query --){int c, s ,e;scanf("%d%d%d",&c ,&s, &e);int ans = bfs(s,e,c);if(ans == -1) cout<<"impossible\n";else cout<<ans<<endl;}return 0;
}

双向BFS

基本思路:

我们只需要从起始状态、目标状态分别开始,两边轮流进行 , 每次各次扩展,当两边各自有一个状态在记录数组中发生重复时,就说明这两个搜索过程相遇了。

如何实现的我们以下边这一题来讲解

噩梦

噩梦

题目大意:
题目是让我们求男孩和女孩是否能相遇,如果能相遇求出最短时间

解题思路:

我们各自对男孩和女孩进行bfs , 如果 记录数组中有交集 就说明能相遇并返回当前所用时间。

关键点:

  1. 如何判断是否是鬼已经占领的地方:我们不需要记录鬼占领的区域,对于每一个坐标我们只需要判断是否被鬼占领即可。如果判断,题目已经明确了是曼哈顿距离。
  2. 如何双向BFS:我们还是利用一个BFS的框架,只不过变成了两个队列。每次我们在循环中依次让两个队列进行个一个队列时候的操作即可。

代码:

#include<stdio.h>
#include<queue>
#include<iostream>
#include<cstring>using namespace std;typedef pair<int, int>PII;const int N = 800;char g[N][N];
PII ghost[2] , boy , girl;
int st[N][N];
int dx[4] = { 1,-1,0,0} , dy[4] = { 0,0,1,-1};
int m ,n;bool check(int x , int y , int tm){if(x < 0 || x >= n || y < 0 || y >= m || g[x][y] == 'X')return false;for(int i = 0 ; i < 2 ; ++i)if(abs(x - ghost[i].first) + abs(y - ghost[i].second) <= 2 * tm) return false;return true;
}int bfs(){memset(st , 0 , sizeof(st));memset(st, 0, sizeof st);int cnt = 0;PII boy, girl;for (int i = 0; i < n; i ++ )for (int j = 0; j < m; j ++ )if (g[i][j] == 'M') boy = {i, j};else if (g[i][j] == 'G') girl = {i, j};else if (g[i][j] == 'Z') ghost[cnt ++ ] = {i, j};queue<PII> qb, qg;qb.push(boy);qg.push(girl);int step = 0;while(qb.size() || qg.size()){step ++ ;for(int i = 0 ; i < 3 ; ++i)for(int j = 0 , len = qb.size(); j < len ; ++j){auto t = qb.front();qb.pop();int x = t.first , y = t.second;if(!check(x,y , step))continue;for(int k = 0 ; k < 4 ; ++k){int xx = x + dx[k] , yy = y + dy[k] ; if(!check(xx,yy , step))continue;if(st[xx][yy] == 2) return step;else if(!st[xx][yy]){ st[xx][yy] = 1 ;qb.push({xx,yy});}}}for(int i = 0 ; i < 1 ; ++i)for(int j = 0 , len = qg.size() ; j < len ; ++j){auto t = qg.front();qg.pop();int x = t.first , y = t.second;if(!check(x,y,step))continue;for(int k = 0 ; k < 4 ; ++k){int xx = x + dx[k] , yy = y + dy[k] ; if(!check(xx,yy , step))continue;if(st[xx][yy] == 1) return step;else if(!st[xx][yy]){st[xx][yy] = 2 ;qg.push({xx,yy});}}}}return -1;}int main(){int T ;scanf("%d" ,&T);while(T--){scanf("%d%d" , &n , &m);for(int i = 0 ; i < n; ++i)scanf("%s" , g[i]);printf("%d\n" , bfs());}return 0;
}

字串变换

子串变换

题目大意:
题目给了起始字符和终止字符和变换规则,让我们求出10步以内能否从起始状态变换到终止状态。

解题思路:

我们从起始和终止状态两边进行BFS , 如果它们在某一层有相交的那么就说明能变化。 注意的点:因为规则只能转换一部分字符,因此,对于没一个都是扩展一层,不是多层也不是单个节点。

关键点:

  1. 对于这里是字符,因此记录步数的话我们可以用哈希表建立起映射关系。
  2. 对于没一个状态我们如何扩展呢?首先是遍历所有规则,对于每一种规则我们都要遍历整个字符串的子串看是否符合规则。 在这里 可以利用substra()来进巧妙的进行。

代码:

#include<iostream>
#include<queue>
#include<string>
#include<unordered_map>using namespace std;const int  N = 6;
string A,B;
string a[N] , b[N];
int n;int extend(queue<string>&qa, unordered_map<string,int> &da , unordered_map<string,int> & db ,string a[N] , string b[N]){int d = da[qa.front()];while(qa.size() && d == da[qa.front()]){auto t = qa.front();qa.pop();for(int i = 0 ; i < n ; ++i)for(int j = 0 ; j < t.size() ; ++j){if(t.substr(j , a[i].size()) == a[i]){string r = t.substr(0 , j ) + b[i] + t.substr(j + a[i].size());if(db.count(r)) return da[t] + db[r] + 1;if(da.count(r)) continue;da[r] = da[t] + 1;qa.push(r);}}}return 11;
}int bfs(){if(A == B )return 0;queue<string>qa,qb;unordered_map<string,int>da,db;da[A] = db[B] = 0;qa.push(A) , qb.push(B);int step = 0 , t;while(qa.size() && qb.size()){if(qa.size() < qb.size()) t = extend(qa,da,db,a,b);else t =extend(qb , db,da, b,a);if(t <= 10)return t;if(++ step == 10)return -1;}return -1;
}int main(){cin>>A>>B;while(cin>>a[n]>>b[n]) n++;int ans = bfs();if(ans == -1)puts("NO ANSWER!");else cout<<ans<<endl;return 0;}

算法之------搜索篇相关推荐

  1. 深度优先搜索_0基础学算法 搜索篇第一讲 深度优先搜索

    0基础学算法 搜索篇第一讲 深度优先搜索 相信绝大多数人对于深度优先搜索和广度优先搜索是不会特别陌生的,如果我这样说似乎你没听说过,那如果我说dfs和bfs呢?先不说是否学习过它们,至少它们的大名应该 ...

  2. 最优化算法python实现篇(4)——无约束多维极值(梯度下降法)

    最优化算法python实现篇(4)--无约束多维极值(梯度下降法) 摘要 算法简介 注意事项 算法适用性 python实现 实例运行结果 算法过程可视化 摘要 本文介绍了多维无约束极值优化算法中的梯度 ...

  3. 最优化算法python实现篇(3)——无约束一维极值(黄金分割法)

    最优化算法python实现篇(3)--无约束一维极值(黄金分割法) 算法适用问题 python实现 示例运行结果 算法适用问题 搜索给定单峰区间的极值问题,一般对凸优化问题比较适用. python实现 ...

  4. 最优化算法python实现篇(2)—无约束一维极值(二分法)

    最优化算法python实现篇(2)--无约束一维极值(二分法) 算法适用问题 python实现 示例运行结果 算法适用问题 搜索给定单峰区间的极值问题,一般对凸优化问题比较适用. python实现 # ...

  5. Java入门算法(贪心篇)丨蓄力计划

    本专栏已参加蓄力计划,感谢读者支持 往期文章 一. Java入门算法(贪心篇)丨蓄力计划 二. Java入门算法(暴力篇)丨蓄力计划 三. Java入门算法(排序篇)丨蓄力计划 四. Java入门算法 ...

  6. OPJ2.5基本算法之搜索200:Solitaire

    OPJ2.5基本算法之搜索200:Solitaire 题目传送门 看网上的题解有点少,我就来水 写一篇博客,给有需要的宝宝们 思路:八维数组!同时搜四个点!干就完了!虽然OPJ的数据水,但还是要有一些 ...

  7. (十一)进阶算法之“搜索排序”

    进阶算法之"搜索排序" 排序和搜索简介 排序和搜索是什么? JS中的排序和搜索 排序算法 搜索算法 Javascript实现:冒泡排序 Javascript实现:选择排序 Java ...

  8. Java入门算法(树篇)

    本专栏已参加蓄力计划,感谢读者支持❤ 往期文章 一. Java入门算法(贪心篇)丨蓄力计划 二. Java入门算法(暴力篇)丨蓄力计划 三. Java入门算法(排序篇)丨蓄力计划 四. Java入门算 ...

  9. Java入门算法(动态规划篇2:01背包精讲)

    本专栏已参加蓄力计划,感谢读者支持❤ 往期文章 一. Java入门算法(贪心篇)丨蓄力计划 二. Java入门算法(暴力篇)丨蓄力计划 三. Java入门算法(排序篇)丨蓄力计划 四. Java入门算 ...

最新文章

  1. 爬虫的系统框架组成-解析器
  2. 图解机器学习:人人都能懂的算法原理(附链接)
  3. rsync+inotify
  4. 从零开始的AI·机器学习の基本概念
  5. idea下org.apache.commons.dbcp.BasicDataSourc找不到
  6. redis的各种数据集的列举功能
  7. IPsec   在企业网中的应用
  8. Bootstrap3 正文文本样式
  9. 行转列经典案例(left join)
  10. 交流电路计算方法:复阻抗和相量法
  11. linux发行版本号列举,查看Linux发行版的名称及其版本号
  12. AWE2021:加速拥抱数字化 开启智慧生活新纪元
  13. 百度闪电算法什么时间开始
  14. 控件:TextView
  15. unity打包游戏后物体的移动速度不一样?
  16. C++作业 设计一个程序实现油桶面积与体积的计算(构造函数与析构函数)
  17. Cesium开发:地下模式效果
  18. 最强大的Docker插件 fabric8io/docker-maven-plugin
  19. Python把mp4视频转化成gif动图
  20. Next.js图片使用

热门文章

  1. Java中测长函数_Core Java测试题
  2. ubuntu如何更改用户名和密码
  3. python numpy 中 np.mean(a) 跟 a.mean() 的区别
  4. python 理解Matplotlib 3D (三维图) 绘图函数 plot_surface 的 rstride 和 cstride参数
  5. 2020新版IDEA创建Web工程(包括添加Tomcat服务器、第三方jar包)
  6. SpringBoot v2.2.6版本遇到的坑 --- HiddenHttpMethodFilter组件的锅
  7. Spring Cloud Alibaba:Sentinel 熔断降级
  8. NioEventLoop加载流程分析
  9. C++获取Windows密码复杂度、密码有效期、密码锁定阀值等安全策略
  10. 计算机基础知识作业,第一章计算机基础知识作业