拿到这道题,很容易写一个 的算法,可是注意
,必通不过此题。但是如果能减少一半的搜索树规模,是能在
内通过
规模的测试样例的,于是我们就想到了双向搜索,具体的做法是:先搜索
,然后将所有可能的重量存入数组,排序之后再搜索
,这样的话对于第二趟搜索得到的每一个重量
,我们去二分查找第一趟得到数组中不大于
的最大项,这部分可以用
实现。为什么区间的
不是
呢?答案是蓝书给的经验公式。一开始我使用了
排序、去重,但是这有两个问题,一是递归树本身就包含了不选的决策,应该在最后一层递归再加入集合,而我在每一次递归都试图放进集合;二是
是大常数数据结构,频繁的插入是程序的性能瓶颈,另外就是没开
。
#include<iostream>
#include<vector>
#include<set>
#include<unordered_set>
#include<algorithm>
int res;
int index;
std::set<int> s;
std::unordered_set<int> u_s;
void forward_DFS(const int& n,const std::vector<int>& v, const int& W,int& curr,int d)
{
s.insert(curr);
if (d == n + 1)
{
return;
}
if (curr + v[d] <= W)
{
curr += v[d];
forward_DFS(n, v, W, curr, d + 1);
curr -= v[d];
}
forward_DFS(n, v, W, curr, d + 1);
}
void backward_DFS(const int& n, const std::vector<int>& v, const int& W, int& curr, int d)
{
if (!u_s.count(curr))
{
auto it = s.upper_bound(W - curr);
if (it != s.begin())
{
it--;
res = std::max(res, *it + curr);
}
u_s.insert(curr);
}
if (d == n + 1)
{
return;
}
if (curr + v[d] <= W)
{
curr += v[d];
backward_DFS(n, v, W, curr, d + 1);
curr -= v[d];
}
backward_DFS(n, v, W, curr, d + 1);
}
int main()
{
int w, n;
std::cin >> w >> n;
std::vector<int> v(50);
for (int i = 1; i <= n; i++)
{
std::cin >> v[i];
}
std::sort(v.begin() + 1, v.end(), std::greater<int>());
int curr = 0;
forward_DFS(n / 2 + 2 , v, w, curr, 1);
backward_DFS(n, v, w, curr, n / 2 + 3);
std::cout << res;
}
然后把用集合的地方换成 再排序,第二个递归的
去掉,
改成
,即可通过此题。
第一次搜索的时间复杂度为
产生的数组长度不会超过 ,那么排序的代价为
第二次搜索会对递归树叶子进行二次查找,复杂度为
最后补一句,这道题去重不去重无所谓,反正我的代码前后只快了 左右。
#include<iostream>
#include<vector>
#include<set>
#include<unordered_set>
#include<algorithm>
long long res;
int index;
//std::set<int> s;
std::vector<int> s;
//std::unordered_set<int> u_s;
void forward_DFS(const int& n,const std::vector<int>& v, const int& W,long long& curr,int d)
{
if (d == n + 1)
{
s.push_back(curr);
return;
}
if (curr + v[d] <= W)
{
curr += v[d];
forward_DFS(n, v, W, curr, d + 1);
curr -= v[d];
}
forward_DFS(n, v, W, curr, d + 1);
}
void backward_DFS(const int& n, const std::vector<int>& v, const int& W, long long& curr, int d,const std::vector<int>::iterator end_it)
{
if (d == n + 1)
{
auto it = std::upper_bound(s.begin(), end_it, W - curr);
if (it != s.begin())
{
it--;
res = std::max(res, *it + curr);
}
return;
}
if (curr + v[d] <= W)
{
curr += v[d];
backward_DFS(n, v, W, curr, d + 1,end_it);
curr -= v[d];
}
backward_DFS(n, v, W, curr, d + 1,end_it);
}
int main()
{
int w, n;
std::cin >> w >> n;
std::vector<int> v(50);
for (int i = 1; i <= n; i++)
{
std::cin >> v[i];
}
std::sort(v.begin() + 1, v.end(), std::greater<int>());
long long curr = 0;
forward_DFS(n / 2 + 2 , v, w, curr, 1);
std::sort(s.begin(), s.end());
auto end_it = std::unique(s.begin(), s.end());
backward_DFS(n, v, w, curr, n / 2 + 3,end_it);
std::cout << res;
}

京公网安备 11010502036488号