双向bfs和双向dfs
1. 算法分析
当进行的变换是可逆的时候,且规定步数的上限时,可以使用双向dfs或双向bfs从源点和终点一起搜索。这样可以把时间从O(n)->O(n/2)
如果dfs调栈超过1e5时,那么考虑双向bfs
写法技巧
-
双向dfs
第一个dfs先搜索前一半的空间,打表存储所有可达的值
第二个dfs搜索后一半的空间,然后查询是否在前一半空间中出现过 -
双向bfs
维护两个队列,当两个队列均非空时才能继续进行循环。循环内不断对元素较少的那个队列进行bfs操作
2. 例题
2.1 双向dfs
acwing171 送礼物
题意:
达达帮翰翰给女生送礼物,翰翰一共准备了N个礼物,其中第i个礼物的重量是G[i]。
达达的力气很大,他一次可以搬动重量之和不超过W的任意多个物品。
达达希望一次搬掉尽量重的一些物品,请你告诉达达在他的力气范围内一次性能搬动的最大重量是多少。N~46, W,G[i]~int
题意: 第一个dfs打表记录前n/2的所有可能和。第二个dfs找到小于等于w-sum的最大的那个
代码:
#include <bits/stdc++.h>
using namespace std;
int const N = 47;
int a[N], cnt = 1, weight[1 << 25], w, n, k, ans;
void dfs1(int u, int sum) {
if (u == k) {
weight[cnt++] = sum;
return;
}
dfs1(u + 1, sum); // 不选第u个
if (sum + 0ll + a[u] <= w) dfs1(u + 1, sum + a[u]); // 选第u个
}
void dfs2(int u, int sum) {
// 当找完后n/2个后,二分查找小于等于w-s的最大值
if (u >= n) {
int l = 0, r = cnt - 1;
while (l < r