【FZU2178】礼物分配

题意ios

  在双胞胎兄弟Eric与R.W的生日会上,他们共收到了N个礼物,生日事后他们决定分配这N个礼物(numv+numw=N)。对于每一个礼物他们俩有着各自心中的价值vi和wi,他们要求各自分到的礼物数目|numv-numw|<=1,而且各自所衡量的礼物价值的差值|sumv-sumw|尽量小,如今他们想知道最小的差值是多少。ide

分析spa

  这是中途相遇法的模板题code

  每一个礼物要么属于Eric,要么属于R.W,因此若是暴力的话是2^30,显然会超。blog

  使用中途相遇法能够将复杂度降到2^15左右,非常神奇。string

 1. 先将N个礼物分红两份,第一份有n/2个礼物,第二份有n-n/2个礼物。it

 2. 而后枚举第一份中有哪些属于Eric,哪些属于R.W。cnt来记录第一份中Eric的礼物数目,sum1是第一份中Eric的礼物价值和,sum2是R.W的礼物价值和。而后用一个vector,把每一个sum1-sum2都加到下标为cnt的vector中。io

 3.  用相似的方法,枚举第二份中哪些属于Eric,哪些属于R.W。sum1,sum2,cnt的含义相同。而后在下标为n-n/2-cnt的vector中找和这个sum1-sum2相加最小的值,而后判断是否要更新ans。模板

  就是这样,用这个题来学中途相遇法了。。。步骤3中的小细节仍是比较神奇的。class

  下面是代码

  

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <iostream>
 4 #include <algorithm>
 5 #include <vector>
 6 #include <map>
 7 
 8 using namespace std;  9 typedef long long LL; 10 
11 const int maxn=35; 12 const int INF=2147000000; 13 int T,n; 14 int v[maxn],w[maxn]; 15 vector<int>V[maxn]; 16 
17 int main(){ 18     scanf("%d",&T); 19     for(int t=1;t<=T;t++){ 20         scanf("%d",&n); 21         for(int i=0;i<=n;i++)V[i].clear(); 22         for(int i=1;i<=n;i++) 23             scanf("%d",&v[i]); 24         for(int i=1;i<=n;i++) 25             scanf("%d",&w[i]); 26         int n1,n2; 27         n1=n/2,n2=n-n1; 28         int cnt; 29  LL sum1,sum2; 30         for(int i=0;i<(1<<n1);i++){ 31             cnt=0,sum1=0,sum2=0; 32             for(int j=0;j<n1;j++){ 33                 if(i&(1<<j)){ 34                     cnt++; 35                     sum1+=v[j+1]; 36                 }else
37                     sum2+=w[j+1]; 38  } 39             V[cnt].push_back(sum1-sum2); 40  } 41 
42         for(int i=0;i<=n1;i++){ 43  sort(V[i].begin(),V[i].end()); 44  V[i].erase(unique(V[i].begin(),V[i].end()),V[i].end()); 45  } 46 
47 
48         int ans=INF; 49         for(int i=0;i<(1<<n2);i++){ 50             cnt=0,sum1=0,sum2=0; 51             for(int j=0;j<n2;j++){ 52                 if(i&(1<<j)){ 53                     cnt++; 54                     sum1+=v[n1+j+1]; 55                 }else{ 56                     sum2+=w[n1+j+1]; 57  } 58  } 59             int cnt1,SUM; 60             cnt1=n2-cnt,SUM=sum1-sum2; 61             vector<int>::iterator it; 62             it=lower_bound(V[cnt1].begin(),V[cnt1].end(),-SUM); 63             if(it!=V[cnt1].end()&&abs(*it+SUM)<ans){ 64                 ans=abs(*it+SUM); 65  } 66             if(it!=V[cnt1].begin()){ 67                 it--; 68                 if(abs(*it+SUM)<ans) 69                     ans=abs(*it+SUM); 70  } 71  } 72         printf("%d\n",ans); 73  } 74 return 0; 75 }
View Code
相关文章
相关标签/搜索