题意:有n个人,每个人一个体重值。要求把这两个人平均分成两部分,使得两部分的体重之和的差最小。
思路:1、背包dp。把所有人总重量的一半当做value上限,背包限重为(n+1)/2,求最接近value的值。
2、随机化.。随机分成两组,然后随机交换。其中对于随机的实验组数,亲测245次WA,250次AC。细节见注释
#include <stdio.h> #include <string.h> #define min(a,b) ((a)<(b)?(a):(b)) #define N 102 int n,m,v[N],dp[45005>>1]; int main(){ int i,j,sum=0; memset(dp, 0, sizeof(dp)); scanf("%d",&n); for(i = 1;i<=n;i++){ scanf("%d",&v[i]); sum += v[i]; } m = (n+1)/2; dp[0] = 1; for(i = 1;i<=n;i++){ for(j = sum/2;j>=0;j--){ if(dp[j] && dp[j]<=m && dp[j+v[i]]<=sum/2){ if(!dp[j+v[i]]) dp[j+v[i]] = dp[j]+1; else dp[j+v[i]] = min(dp[j+v[i]],dp[j]+1); } } } for(i = sum/2;i>=0;i--) if(dp[i]){ printf("%d %d\n",i,sum-i); break; } return 0; }
随机代码:
#include <stdio.h> #include <string.h> #include <stdlib.h> #include <math.h> #define min(a,b) ((a)<(b)?(a):(b)) #define max(a,b) ((a)>(b)?(a):(b)) #define N 102 int n,m,a[N],s[N],t[N]; int main(){ int i,j,sum,s1,s2,T=250,temp1,temp2,len1,len2,flag,res1=0;//T是随机的实验组数,亲测245WA,250AC s1 = s2 = sum = 0; scanf("%d",&n); for(i = 0;i<n;i++){ scanf("%d",&a[i]); sum += a[i]; } if(n==1){ printf("0 %d\n",a[0]); return 0; } m = n - n/2; n /= 2; while(T--){ len1 = len2 = flag = s1 = s2 = 0; for(i = 0;len1<n && len2<m;i++){//将数据随机分成两份 if(rand()%2){ t[len2++] = a[i]; s2 += a[i]; } else{ s[len1++] = a[i]; s1 += a[i]; } } while(len1 < n){ s1 += a[i]; s[len1++] = a[i++]; } while(len2 < m){ s2 += a[i]; t[len2++] = a[i++]; } while(flag<10){ i = rand()%n;//在两份数据中任选一个进行调换 j = rand()%m; temp1 = abs(s1 - s2); temp2 = abs(s1 - s2 - 2*(s[i]-t[j])); if(temp1 > temp2){//如果调换结果更好,那么进行调换 flag = 0; s1 -= s[i]-t[j]; s2 -= t[j]-s[i]; temp1 = s[i]; s[i] = t[j]; t[j] = temp1; } flag++;//flag保存有多少次没有进行过更新了 } res1 = max(res1,min(s1,s2)); } printf("%d %d\n",res1,sum-res1); return 0; }