现在有n枚金币,它们可能会有不同的价值,现在要把它们分成两部分,要求这两部分金币数目之差不超过1,问这样分成的两部分金币的价值之差最小是多少?
meet in the middle 搞定
#include<bits/stdc++.h> using namespace std; int t,n,a[31]; struct node{ int c; long long v; }b[1000001],b1[1000001]; int r[1000001],cnt[1000001]; int cmp(node x,node y){ if(x.c==y.c)return x.v<y.v; else return x.c<y.c; } int l[1000001],val[1000001]; int calc(int x,int t){ int i; int ans=0; for(i=0;i<15;i++)ans+=(x>>i)&1?a[i+t]:0; return ans; } int main(){ int i; cin>>t; for(i=0;i<(1<<15);i++)cnt[i]=cnt[i>>1]+(i&1); while(t--){ scanf("%d",&n); long long sum=0; for(i=0;i<n;i++)scanf("%d",&a[i]),sum+=a[i]; int m=n>>1,k=n-m; for(i=0;i<(1<<m);i++)b[i]=(node){cnt[i],calc(i,0)}; sort(b,b+(1<<m),cmp); for(i=0;i<1<<m;i++)val[i]=b[i].v; l[0] = 0;l[m + 1] = 1 << m; for(i=1;i<1<<m;i++)if(b[i].c!=b[i-1].c)l[b[i].c]=i; long long ans=1e15; for(i=0;i<(1<<k);i++){ int c=(m-cnt[i]),w=calc(i,m); if(~c){ int pos=lower_bound(val+l[c],val+l[c+1],sum/2-w)-val; if(pos<l[c+1])ans=min(ans,abs(2*(val[pos]+w)-sum)); if(pos>l[c])ans=min(ans,abs(2*(val[pos-1]+w)-sum)); } } cout<<ans<<endl; } return 0; }