POJ 2576 Tug of War 二维背包 OR 随机化

来源:互联网 发布:java 继承多个类 编辑:程序博客网 时间:2024/05/16 08:25

点击打开链接

题意:n个人n<=100,每个人有权值a[i]<=450,要求把n个人分成两组,人数差<=1&&权值差最小
dp(i)[j][k]前i个人选j个是否能凑出权值为k? n为奇数可以选half or half-1 n为偶数 只能选half个 复杂度O(n*n*M) 

#include <iostream>#include <algorithm>#include <cstdio>#include <cstring> using namespace std;typedef long long ll;const int N=1e2+20;const int M=455;int dp[N][N*M];//dp(i)[j][k]前i个人选j个是否能凑出权值为k? int n,a[N]; int main(){while(cin>>n){int sum=0,s;memset(dp,0,sizeof(dp));dp[0][0]=1;for(int i=1;i<=n;i++)cin>>a[i],sum+=a[i];int half=(n+1)/2;s=sum;sum/=2;for(int i=1;i<=n;i++){//逆推保证dp[j-1][k-a[i]]是前i-1个人中选出的for(int j=half;j>=1;j--){for(int k=sum;k>=a[i];k--){//cout<<j<<' '<<a[i]<<' '<<k<<endl;dp[j][k]|=dp[j-1][k-a[i]];}}}int j;for(j=sum;j>=0;j--){if(n%2){if(dp[half][j]||dp[half-1][j])break;}else{if(dp[half][j])break;}}cout<<min(j,s-j)<<' '<<max(j,s-j)<<endl; }return 0;}
随机化:步骤一:随机分成两组 步骤二:不断随机交换两个数 若更优 则交换 否则继续随机直到一定次数后返回步骤1

代码参考链接

#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 102int 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;}



0 0
原创粉丝点击