https://ac.nowcoder.com/acm/contest/889/D
题意:n个数字(最多36),求一个子集,和为s。
思路:搜索复杂度
O
(
2
36
)
O(2^{36})
O(236),即便剪枝,也差得远。
应当用中途相遇法。把前一半的子集状压算出来,后一半枚举过程中,二分找前一半有没有s-sum。
复杂度
O
(
2
n
/
2
l
o
g
(
n
)
)
O(2^{n/2}log(n))
O(2n/2log(n))
#include<bits/stdc++.h>
using namespace std;
#define ll long long
ll n,s,a[40];
vector<pair<ll,int> > x;
int main()
{
//freopen("input.in","r",stdin);
cin>>n>>s;
for(int i=0;i<n;i++)cin>>a[i];
for(int st=1;st<(1<<(n/2));st++)
{
ll sum=0;
for(int i=0;i<(n/2);i++)if((1<<i)&st)sum+=a[i];
x.push_back(make_pair(sum,st));
}
sort(x.begin(),x.end());
for(int st=1;st<(1<<(n-n/2));st++)
{
ll sum=0;
for(int i=0;i<(n-n/2);i++)if((1<<i)&st)sum+=a[i+n/2];
int p=lower_bound(x.begin(),x.end(),make_pair(s-sum,0))-x.begin();
if(p<x.size() && x[p].first==s-sum)
{
for(int i=0;i<n/2;i++)if((1<<i)&x[p].second)putchar('1'); else putchar('0');
for(int i=0;i<(n-n/2);i++)if((1<<i)&st)putchar('1'); else putchar('0');
break;
}
}
return 0;
}