POJ 3977

折半搜索。
学到了map.lower_bound;
先做前面再做后面,就是基本的折半搜索,难点在于如何去处理,不能为空集。
这里我每一次状态都是从1开始,表示从不为空。
然后单独再每一半搜索中,更新一下最值。
然后再合起来更新。

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<stack>
#include<vector>
#include<queue>
#include<set>
#include<map>
#define up(i,a,b)  for(int i=a;i<b;i++)
#define dw(i,a,b)  for(int i=a;i>b;i--)
#define upd(i,a,b) for(int i=a;i<=b;i++)
#define dwd(i,a,b) for(int i=a;i>=b;i--)
//#define local
typedef long long ll;
const double esp = 1e-6;
const double pi = acos(-1.0);
const long long INF = 0x3f3f3f3f;
using namespace std;
typedef pair<int, int> pir;
int n;
ll a[40];
ll abs1(ll sum)
{
	if (sum < 0)
		return -sum;
	else return sum;
}
pair<ll,int> solve()
{
	int mid = n / 2;
	ll ng=0;
	int cnt = 0;
	pair<ll, int > res = make_pair(abs1(a[0]), 1);
	map<ll, int> mp;
	up(i, 1, (1<<mid))
	{
		ng = 0;
		cnt = 0;
		up(j, 0, mid)
		{
			if (i >> j & 1)
			{
				ng+= a[j];
				cnt++;
			}
		}
		res = min(res, make_pair(abs1(ng), cnt));
		if (mp[ng] != 0)
		{
			mp[ng] = min(mp[ng], cnt);
		}
		else
		{
			mp[ng] = cnt;
		}
	}
	up(i, 1, (1 << (n - mid)))
	{
		ng = 0;
		cnt = 0;
		up(j, 0, (n - mid))
		{
			if (i >> j & 1)
			{
				ng += a[mid + j];
				cnt++;
			}
		}

		res = min(res, make_pair(abs1(ng), cnt));
		map<ll, int>::iterator it = mp.lower_bound(-ng);
		if (it != mp.end())
		{
			res = min(res, make_pair(abs1(it->first + ng), it->second + cnt));
		}
		if (it != mp.begin())
		{
			it--;
			res = min(res, make_pair(abs1(it->first + ng), it->second + cnt));
		}
	}
	return res;
}
int main() {
	while (cin >> n && n)
	{
		up(i, 0, n)
		{
			scanf("%lld", &a[i]);
		} 
		pair<ll,int> ans = solve();
		cout << ans.first<<" "<< ans.second<<endl;
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_44019404/article/details/88669498
POJ