POJ 3977 Subset | 折半搜索

题目:

给出一个整数集合,求出非空子集中元素和绝对值最小是多少(元素个数尽量少)


题解:

分成两半

爆搜每一半,用map维护前一半的值

每搜出后一半的一个值就去map里找和他和绝对值最小的更新答案

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<map>
typedef long long ll;
using namespace std;
ll n,a[50],ans,tmp,ok;
map <ll,ll> mp;
map <ll,ll> :: iterator it;
ll Abs(ll x){ return x>0?x:-x;}
void DfsFront(ll step,ll state,ll val)
{
    if (step>n/2)
    {
	it=mp.find(val);
	if (it!=mp.end())
	    mp[val]=min(mp[val],state);
	else
	    mp[val]=state;
	if (Abs(val)<ans && state!=0)
	    ans=Abs(val),tmp=state;
	if (Abs(val)==ans && state<tmp && state!=0)
	    tmp=state;
	return ;
    }
    DfsFront(step+1,state,val);
    DfsFront(step+1,state+1,val+a[step]);
}
void DfsBack(ll step,ll state,ll val)
{
    if (step>n)
    {
	it=mp.lower_bound(-val);
	ll w=it->first;
	if (it!=mp.end() && Abs(val+w)<ans && it->second+state!=0)
	    ans=Abs(val+w),tmp=it->second+state;
	if (it!=mp.end() && Abs(val+w)==ans && mp[w]+state<tmp && mp[w]+state!=0)
	    tmp=mp[w]+state;
	if (it!=mp.begin()) it--;
	if (it!=mp.end())
	{
	    w=it->first;
	    if (Abs(val+w)<ans && state+it->second!=0)
		ans=Abs(val+w),tmp=it->second+state;
	    if (Abs(val+w)==ans && it->second+state<tmp && it->second!=0)
		tmp=it->second+state;
	}
	return ;
    }
    DfsBack(step+1,state,val);
    DfsBack(step+1,state+1,val+a[step]);
}
int main()
{
    while (scanf("%lld",&n)!=0,n)
    {
	mp.clear();
	ans=mp[0]=0;
	for (int i=1;i<=n;i++)
	    scanf("%lld",&a[i]),ans+=233+Abs(a[i]);
	DfsFront(1,0,0);
	DfsBack(n/2+1,0,0);
	printf("%lld %lld\n",ans,tmp);
    }
    return 0;
}

 

posted @ 2017-12-15 15:46  MSPqwq  阅读(135)  评论(0编辑  收藏  举报