题目地址:FZU 2178
由于n最大是30,一次全搜的话妥妥的超时,那么可以采用折半搜索。分成相同的两份,对左边的一堆进行预处理,然后再处理右堆,每一次都对左堆进行二分,找最接近的。由于两个人取的不能相差多于1个,所以要对每个个数分开存储。并排序,排序是为了后边的二分。
代码如下:
#include <iostream> #include <string.h> #include <math.h> #include <queue> #include <algorithm> #include <stdlib.h> #include <map> #include <set> #include <stdio.h> using namespace std; #define LL __int64 #define pi acos(-1.0) const int mod=1e9+7; const int INF=1e9; const double eqs=1e-9; int v[40], w[40], c[17][1<<15], d[17]; int bin_search(int x, int f) { int low=0, mid, high=d[f]-1, ans=-1; while(low<=high){ mid=low+high>>1; if(c[f][mid]>=x) { ans=mid; high=mid-1; } else low=mid+1; } if(ans==-1){ return abs(c[f][d[f]-1]-x); } else if(ans==0){ return abs(c[f][0]-x); } else return min(abs(c[f][ans]-x),abs(c[f][ans-1]-x)); } int main() { int t, n, i, min1, tot, m1, m2, ans1, ans2, al, ans, j, cnt; //freopen("1.txt","r",stdin); //freopen("2.txt","w",stdout); scanf("%d",&t); while(t--){ scanf("%d",&n); m1=n>>1; m2=n-m1; min1=INF; for(i=0;i<n;i++){ scanf("%d",&v[i]); } for(i=0;i<n;i++){ scanf("%d",&w[i]); } if(n==1){ printf("%d\n",min(abs(v[0]-w[1]),abs(w[0]-v[1]))); continue ; } tot=1<<m1; memset(d,0,sizeof(d)); memset(c,0,sizeof(c)); for(i=0;i<tot;i++){ ans1=ans2=cnt=0; for(j=0;j<m1;j++){ if(i&(1<<j)) { ans1+=v[j]; cnt++; } else ans2+=w[j]; } c[cnt][d[cnt]++]=ans1-ans2; } for(i=0;i<=m1;i++){ sort(c[i],c[i]+d[i]); } al=1<<m2; for(i=0;i<al;i++){ ans1=ans2=0; cnt=0; for(j=0;j<m2;j++){ if(i&(1<<j)) { ans1+=v[j+m1]; cnt++; } else ans2+=w[j+m1]; } ans=ans2-ans1; //printf("%d\n",ans); if((n&1)&&cnt){ min1=min(bin_search(ans,n/2+1-cnt),min1); } min1=min(bin_search(ans,n/2-cnt),min1); } printf("%d\n",min1); } return 0; }
时间: 2024-10-08 18:42:05