TZOJ 1503 Incredible Cows(折半搜索+二分)

描述

Farmer John is well known for his great cows. Recently, the cows have decided to participate in the Incredible Cows Puzzle Contest (ICPC).

Farmer John wants to divide the cows into two teams, and he wants to minimize the difference of Puzzle Solving Power of two teams.

Puzzle Solving Power of a team is sum of Puzzle Solving Power of cows forming that team.

Help F.J. to find the minimum difference!

输入

The first line of input consists of a single integer T, the number of test-cases. Each test-case consists of a line containing n (2 <= n <= 34), number of cows. n lines follow. i-th line contains the Puzzle Solving Power of i-th cow. Puzzle Solving Power of a cow is a non-negative number less than 10,000,000. There is a blank line between two consecutive test-cases.

输出

For each test-case, output a line containing the minimum difference which can be achieved.

样例输入

2
3
12
6
6

10
123
455
1000
403
234
554
129
454
84
11

样例输出

0
5

题意

把n数分成两堆,使得两堆和的差最小。

题解

n高达34,直接爆搜肯定不行。但是17可以直接爆搜(2^17)。

于是乎,相当于把数组对半拆开,记和为suml和sumr,然后爆搜出两堆的所有情况。

然后就是配对问题了,假设第一堆取出了X,第二堆取出了Y。

答案是最小化函数|(X+Y)-((suml-X)+(sumr-Y))|,化简得到|2X+2Y-suml-sumr|。

我们枚举一个未知数X,那么变成绝对值函数,易得Y>=(suml+sumr)/2-X,于是lower_bound找到最小的Y。

这是最小值在右边的情况,还有在左的情况就是二分得到的Y前一个数。

时间复杂度O(2^17*log(2^17))。

代码

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 
 4 #define ll long long
 5 ll a[35];
 6 set<ll>se[2];
 7 void dfs(int s,int t,bool f,ll sum)
 8 {
 9     if(s>t)
10     {
11         se[f].insert(sum);
12         return;
13     }
14     dfs(s+1,t,f,sum+a[s]);
15     dfs(s+1,t,f,sum);
16 }
17 int main()
18 {
19     int n,t;
20     cin>>t;
21     while(t--)
22     {
23         se[0].clear(),se[1].clear();
24         cin>>n;ll suml=0,sumr=0;
25         for(int i=1;i<=n/2;i++)cin>>a[i],suml+=a[i];
26         for(int i=n/2+1;i<=n;i++)cin>>a[i],sumr+=a[i];
27         dfs(1,n/2,0,0);dfs(n/2+1,n,1,0);
28         ll min_abs=1e18;
29         set<ll>::iterator it,itt;
30         for(auto X:se[0])
31         {
32             it=se[1].lower_bound((suml+sumr)/2-X);
33             itt=it;
34             if(it!=se[1].begin())--itt;
35             if(it==se[1].end())--itt,--it;
36             min_abs=min(min_abs,min(abs(suml+sumr-2*X-2*(*it)),abs(suml+sumr-2*X-2*(*it))));
37         }
38         cout<<min_abs<<'\n';
39     }
40     return 0;
41 }

猜你喜欢

转载自www.cnblogs.com/taozi1115402474/p/11960263.html