- 双向搜索
除了迭代加深之外,双向搜索也可以避免在深层子树上浪费时间。在一些题目 中,问题不但具有“初态”, 还具有明确的“终态”,并且从初态开始搜索与从终态开始逆向搜索产生的搜索树都能覆盖整个状态空间。在这种情况下,就可以采用双向搜索一从初态和终态出发各搜索一半状态, 产生两棵深度减半的搜索树,在中间交会、组合成最终的答案。
如下图,左侧是直接进行次搜索产生的搜索树,右侧是双向搜索的两棵搜索树,避免了层数过深时分支数量的大规模增长。
- 例题
题目大意
达达帮翰翰给女生送礼物,翰翰一共准备了N个礼物,其中第i个礼物的重量是G[i]。
达达的力气很大,他一次可以搬动重量之和不超过W的任意多个物品。
达达希望一次搬掉尽量重的一些物品,请你告诉达达在他的力气范围内一次性能搬动的最大重量是多少。
输入格式
第一行两个整数,分别代表W和N。
以后N行,每行一个正整数表示G[i]。
输出格式
仅一个整数,表示达达在他的力气范围内一次性能搬动的最大重量。
数据范围
1≤N≤46,
1≤W,G[i]≤231−1
样例
输入样例:
20 5
7
5
4
18
1
输出样例:
19
代码
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
using namespace std;
typedef long long ll;
const int N = 50;
int a[N];
int n, m, k;
int w[1 << 24];
int cnt, ans;
void dfs_1(int u, int s){
if(u == k){
w[cnt++] = s;
return ;
}
if((ll)s + a[u] <= m) dfs_1(u + 1, s + a[u]);
dfs_1(u + 1, s);
}
void dfs_2(int u, int s){
if(u == n){
int l = 0, r = cnt - 1;
while(l < r){
int mid = (l + r + 1) >> 1;
if((ll)w[mid] + s <= m) l = mid;
else r = mid - 1;
}
if((ll)w[r] + s <= m) ans = max(ans, w[r] + s);
return ;
}
if((ll)s + a[u] <= m) dfs_2(u + 1, s + a[u]);
dfs_2(u + 1, s);
}
int main(){
scanf("%d%d", &m, &n);
for(int i = 0; i < n; i++){
scanf("%d", &a[i]);
}
sort(a, a + n);
reverse(a, a + n);
k = n / 2 + 2;
dfs_1(0, 0);
sort(w, w + cnt);
cnt = unique(w, w + cnt) - w;
dfs_2(k, 0);
printf("%d\n", ans);
return 0;
}