中途相遇法

FZU  2178】礼物分配(经典题)

<span style="font-size:14px;"><span style="font-size:14px;">#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <string>
#include <vector>
#include <math.h>
using namespace std;
int v[35],w[35];
vector<int>vec[40];
int main() 
{
	int n,t;
	scanf("%d",&t);
	while(t--)
	{
		scanf("%d",&n);
		for(int i=0;i<n;i++) scanf("%d",&v[i]);
		for(int i=0;i<n;i++) scanf("%d",&w[i]);
		for(int i=0;i<=n;i++) vec[i].clear();
		int half=n/2;
		for(int i=0;i<(1<<half);i++)
		{
			int cnt=0,sum1=0,sum2=0;
			for(int j=0;j<half;j++)
			{
				if(i&(1<<j))
				{
					sum1+=v[j];
					cnt++;
				}
				else
				{
					sum2+=w[j];
				}
			}
			vec[cnt].push_back(sum1-sum2);
		}
		for(int i=0;i<=half;i++) 
		{
			sort(vec[i].begin(),vec[i].end());
			vec[i].erase(unique(vec[i].begin(),vec[i].end()),vec[i].end());
		}
		int ans=0x3f3f3f3f;
		for(int i=0;i<(1<<(n-half));i++)
		{
			int cnt=0,sum1=0,sum2=0;
			for(int j=0;j<(n-half);j++)
			{
				if(i&(1<<j))
				{
					sum1+=v[j+half];
					cnt++;
				}
				else
				{
					sum2+=w[j+half];
				}
			}
			vector<int>::iterator iter; 
			int p=n-half-cnt,sum=sum1-sum2;
			iter=lower_bound(vec[p].begin(),vec[p].end(),-sum);
			if(iter!=vec[p].end() && abs(*iter+sum)<ans)
			{
				ans=abs(*iter+sum);
			}
     		if(iter!=vec[p].begin())
			{
				--iter;
				if(ans>abs(*iter+sum)) ans=abs(*iter+sum);
			}
		}
		printf("%d\n",ans);
	}
	return 0;
}</span></span>

UVALive 2965】 Jurassic Remains  (即UVA 1326、POJ 1903)

大白书P57  例题25

<span style="font-size:14px;"><span style="font-size:14px;">#include <bits/stdc++.h>
using namespace std;
map<int,int>table;
int a[30];
char s[1000];
int bitcount(int x)
{
	return x == 0 ? 0 : bitcount(x/2) + (x&1);
}
int main()
{
	int n;
	while(~scanf("%d",&n) && n)
	{
		memset(a,0,sizeof(a));
		for(int i=0;i<n;i++)
		{
			scanf("%s",s);
			for(int j = 0; s[j] != '\0'; j++)
			{
				a[i] ^= (1 << (s[j]-'A'));
			}
		}
		table.clear();
		int n1=n/2,n2=n-n1;
		for(int i = 0 ; i < (1 << n1) ; i++)
		{
			int x = 0;
			for(int j = 0 ; j < n1 ; j++)
			{
				if(i & (1 << j))
				{
					x ^= a[j];
				}
			}
			map<int, int>::iterator fi=table.find(x);
			if(fi==table.end() || bitcount(table[x]) < bitcount(i)) table[x] = i;
		}
		int ans=0;
		for(int i = 0; i < (1<<n2); i++)
		{
			int x=0;
			for(int j = 0; j < n2; j++)
			{
				if(i & (1 << j)) 
				{
					x ^= a[n1+j];
				}
			}
			map<int, int>::iterator fi=table.find(x);
			if(fi!=table.end() && bitcount(ans) < bitcount(table[x]) + bitcount(i))
			{
				ans = (i << n1) ^ table[x];
			}
		}
		printf("%d\n",bitcount(ans));
		for(int i = 0; i < n; i++)
		{
			if(ans & (1 << i))
			{
				printf("%d ",i+1);
			}
		}
		printf("\n");
	}
	return 0;
} </span></span>

POJ 3977】Subset

找出和的绝对值最小的子集,输出和,以及子集个数

<span style="font-size:14px;">#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <string>
#include <map>
using namespace std;
#define ll __int64
map<ll, int>table;
ll a[40];
ll ll_abs(ll x)
{
	return x<0 ? -x : x;
}
int main()
{
	int n;
	while(~scanf("%d", &n) && n)
	{
		for(int i = 0; i < n; i++)
		{
			scanf("%I64d", &a[i]);
		}
		int n1 = n/2, n2 = n-n1;
		table.clear();
		pair<ll, int>result(ll_abs(a[0]), 1); //存最小的 
		for(int i = 0; i < (1<<n1); i++)
		{
			ll ans = 0;
			int ni = 0;
			for(int j = 0; j < n1; j++)
			{
				if(i & (1<<j))
				{
					ans += a[j];
					ni++;
				}
			}
			if(ni == 0) continue;
			result = min(result, make_pair(ll_abs(ans), ni));
			//pair中先比较first的位置,在比较second的位置上的值 
			if(!table.count(ans) || table[ans] > ni) 
				table[ans]=ni;
		}
		ll sum = 0x7FFFFFFF;
		int num = 100;
		for(int i = 0; i < (1<<n2); i++)
		{
			ll ans = 0;
			int ni = 0;
			for(int j = 0; j < n2; j++)
			{
				if(i & (1<<j))
				{
					ans += a[n1+j];
					ni++;
				}
			}
			if(ni == 0) continue;
			result = min(result, make_pair(ll_abs(ans), ni));
			map<ll , int>:: iterator fi = table.lower_bound(-ans);
			int s1, s2;
			if(fi != table.end()) 
			{
				result = min(result, make_pair(ll_abs(fi->first+ans), ni+fi->second));
			}
			if(fi != table.begin())
			{
				--fi;
				result = min(result, make_pair(ll_abs(fi->first+ans), ni+fi->second));
			}
		}
		printf("%I64d %d\n",result.first,result.second);
	}
	return 0;
}</span>

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值