题目分析:
我们可以用01表示物品的归属。
用中途相遇法,将物品平均分成两堆,一堆暴力得到这一堆物品能构成的所有方案,另一堆对每一个方案,都在暴力的一堆中二分找到最接近的解,更新最优值。(奇数个物品则保证暴力的一堆比二分的一堆多一个)。暴力的一堆的方案可以按照属于其中一个人的物品的个数分类,然后每一类排个序,以便满足二分的性质。
代码如下:
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
//#include <cmath>
using namespace std ;
typedef long long LL ;
#pragma comment ( linker , "/STACK:1024000000" )
#define rep( i , a , b ) for ( int i = ( a ) ; i < ( b ) ; ++ i )
#define For( i , a , b ) for ( int i = ( a ) ; i <= ( b ) ; ++ i )
#define rev( i , a , b ) for ( int i = ( a ) ; i >= ( b ) ; -- i )
#define rec( i , A , o ) for ( int i = A[o] ; i != o ; i = A[i] )
#define clr( a , x ) memset ( a , x , sizeof a )
const int INF = 0x3f3f3f3f ;
struct Node {
int v , w ;
} ;
Node node[31] ;
int a[16][40000] ;
int n , half ;
int ans ;
int search ( int x , int o ) {
int l = 1 , r = a[o][0] ;
while ( l < r ) {
int m = ( l + r ) >> 1 ;
if ( a[o][m] >= x ) r = m ;
else l = m + 1 ;
}
return l ;
}
void dfs ( int cur , int cnt = 0 , int val = 0 ) {
if ( cur == half + 1 ) {
a[cnt][++ a[cnt][0]] = val ;
return ;
}
dfs ( cur + 1 , cnt + 1 , val + node[cur].v ) ;
dfs ( cur + 1 , cnt + 0 , val - node[cur].w ) ;
}
void dfs2 ( int cur , int cnt = 0 , int val = 0 ) {
if ( cur == n + 1 ) {
if ( cnt > 1 && abs ( n-2*half-2 ) <= 1 ) {
int x = search ( val , cnt - 1 ) ;
ans = min ( ans , abs ( val - a[cnt - 1][x] ) ) ;
if ( x > 1 ) ans = min ( ans , abs ( val - a[cnt - 1][x - 1] ) ) ;
if ( x < a[cnt - 1][0] ) ans = min ( ans , abs ( val - a[cnt - 1][x + 1] ) ) ;
}
if ( cnt < half && abs ( n-2*half+2 ) <= 1 ) {
int x = search ( val , cnt + 1 ) ;
ans = min ( ans , abs ( val - a[cnt + 1][x] ) ) ;
if ( x > 1 ) ans = min ( ans , abs ( val - a[cnt + 1][x - 1] ) ) ;
if ( x < a[cnt + 1][0] ) ans = min ( ans , abs ( val - a[cnt + 1][x + 1] ) ) ;
}
int x = search ( val , cnt ) ;
ans = min ( ans , abs ( val - a[cnt][x] ) ) ;
if ( x > 1 ) ans = min ( ans , abs ( val - a[cnt][x - 1] ) ) ;
if ( x < a[cnt][0] ) ans = min ( ans , abs ( val - a[cnt][x + 1] ) ) ;
return ;
}
dfs2 ( cur + 1 , cnt + 0 , val - node[cur].v ) ;
dfs2 ( cur + 1 , cnt + 1 , val + node[cur].w ) ;
}
void solve () {
ans = INF ;
scanf ( "%d" , &n ) ;
For ( i , 1 , n ) scanf ( "%d" , &node[i].v ) ;
For ( i , 1 , n ) scanf ( "%d" , &node[i].w ) ;
half = ( n + 1 ) / 2 ;
For ( i , 0 , half ) a[i][0] = 0 ;
dfs ( 1 ) ;
For ( i , 0 , half ) sort ( a[i] + 1 , a[i] + a[i][0] + 1 ) ;
dfs2 ( half + 1 ) ;
printf ( "%d\n" , ans ) ;
}
int main () {
int T ;
scanf ( "%d" , &T ) ;
while ( T -- ) solve () ;
return 0 ;
}