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;
}

 

转载于:https://www.cnblogs.com/mrsheep/p/8043439.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值