传送门
一道看似是贪心实则是DP的题目,只是DP的不直接是答案
设DP[i][j]为用i个人能否能达到j的重量(还有一维用滚动数组搞掉了)
DP[i][j]=DP[i][j]||DP[i][j-w[k]],初始状态DP[0][0]=DP[1][0]=1
然后找n/2个人所能达到最接近∑w/2的体重就行了
#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
int w[9999];
bool f[9999][999];
int main()
{
f[0][0]=1;
f[1][0]=1;
int n;
int tot=0;
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&w[i]),tot+=w[i];
int s=tot;
if(tot%2) tot+=1;
int k;
if(n%2) k=(n+1)/2;
else k=n/2;
for(int i=1;i<=n;i++)
for(int j=tot;j>=w[i];j--)
for(int q=k;q>=1;q--)
int i;
for(i=tot;i>=0;i--)
if(f[k][i]) break;
printf("%d %d",min(i,s-i),max(i,s-i));
}
方法2:随机化贪心
我们就认为前n/2个是第一组的,每次算出前n/2的和,然后算出两组的差值
循环100000次,随机出2*n的数互换位置,随机出答案
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<ctime>
using namespace std;
int ans=1e9;
int a[99999];
int maxf;
int main()
{
int n;
srand(time(0));
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",a+i),maxf+=a[i];
for(int i=1;i<=110000;i++)
{
for(int j=1;j<=n;j++)
{
int x=rand()%n+1;
int y=rand()%n+1;
swap(a[x],a[y]);
}
int sum=0;
for(int j=1;j<=n/2;j++)
sum+=a[j];
ans=min(ans,abs(maxf-2*sum));
}
//printf("%d\n",ans);
printf("%d %d",(maxf-ans)/2,(maxf+ans)/2);
return 0;
}