【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
相關文章
相關標籤/搜索