搜索优化技巧:双向搜索

  • 双向搜索

       除了迭代加深之外,双向搜索也可以避免在深层子树上浪费时间。在一些题目 中,问题不但具有“初态”, 还具有明确的“终态”,并且从初态开始搜索与从终态开始逆向搜索产生的搜索树都能覆盖整个状态空间。在这种情况下,就可以采用双向搜索一从初态和终态出发各搜索一半状态, 产生两棵深度减半的搜索树,在中间交会、组合成最终的答案。

       如下图,左侧是直接进行次搜索产生的搜索树,右侧是双向搜索的两棵搜索树,避免了层数过深时分支数量的大规模增长。
在这里插入图片描述

  • 例题

题目大意

达达帮翰翰给女生送礼物,翰翰一共准备了N个礼物,其中第i个礼物的重量是G[i]。

达达的力气很大,他一次可以搬动重量之和不超过W的任意多个物品。

达达希望一次搬掉尽量重的一些物品,请你告诉达达在他的力气范围内一次性能搬动的最大重量是多少。

输入格式
第一行两个整数,分别代表W和N。

以后N行,每行一个正整数表示G[i]。

输出格式
仅一个整数,表示达达在他的力气范围内一次性能搬动的最大重量。

数据范围
1≤N≤46,
1≤W,G[i]2311

样例

输入样例:
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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值