题意:
找到不超过w的最大和
思路:
首先这道题目肯定是要搜索的,因为如果说用DP做的话,那么这个W值太大了,但是如果说只是普通搜索的话,那么O(2^N)的复杂度足以超时,而且这道题目重点就是,我们已经知道了初态而且还知道了终态,既然如此的话,我们可以选择双向搜索.
根据双向搜索的性质,我们大致可以确定当前搜索的范围,首先从前一半个物品中,挑选任意多个物品,然后将这些物品的权值总和加入到数组S中,然后我们就会发现在这个S数组中有很多很多的重复的数值,既然如此,我们不妨将他们统统都删掉,至于如何删掉,相信STL中的unique可以满足需求.然后我们现在前半部分搜索完后,开始搜索后半部分,至于后半部分搜索,其实和前半部分一模一样,只是我们需要二分找到当前可以填写的最大值.
AC代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e7+10;
ll ans,n,m,a[N],s[N],n_2;
ll find(int val)//二分查找
{
int l=1,r=n_2,check=m-val;//最大可以承受的值
while(l<r) {
int mid=(l+r+1)>>1;
if (s[mid]<=check) {
l=mid;
} else {
r=mid-1;
}
}
ans=max(ans,s[l]+val);
}
int dfs(int x,ll sum)
{
if(x==(n/2+2)+1) {
s[++n_2]=sum;//新的权值出现,压入数组中
return true;
}
dfs(x+1,sum);//不放
if(sum+a[x]<=m) {//放
dfs(x+1,sum+a[x]);
}
}
int dfs2(int x,int sum)
{
if (x==n+1) {
find(sum);//求出当前可以填充的最大值
return true;
}
dfs2(x+1,sum);
if (sum+a[x]<=m) {
dfs2(x+1,sum+a[x]);
}
}
int main()
{
cin>>m>>n;
for(int i=1;i<=n;i++)cin>>a[i];
sort(a+1,a+1+n,greater<int>());
dfs(1,0);
sort(s+1,s+n_2+1);
n_2=unique(s+1,s+n_2+1)-(s+1);//去掉重复数
dfs2(n/2+3,0);
cout<<ans<<endl;
}