【SSL】1638拔河比赛

【SSL】1638拔河比赛

Time Limit:1000MS
Memory Limit:65536K

Description

一个学校举行拔河比赛,所有的人被分成了两组,每个人必须(且只能够)在其中的一组,要求两个组的人数相差不能超过1,且两个组内的所有人体重加起来尽可能地接近。

Input

输入数据的第1行是一个n,表示参加拔河比赛的总人数,n<=100,接下来的n行表示第1到第n个人的体重,每个人的体重都是整数(1<=weight<=450)。

Output

输出数据应该包含两个整数:分别是两个组的所有人的体重和,用一个空格隔开。注意如果这两个数不相等,则请把小的放在前面输出。

Sample Input

3
100
90
200

Sample Output

190 200

思路

假设f[i,j,k]表示在前i个人中选j个人在一组,他们的重量之和等于k是否可能。
f[i,j,k]是bool型,其值为true代表有可能,false代表没有可能。
⑴第i个人没有被选中,此时就和从前面i-1个人中选出j个人的方案没区别,
所以f[i,j,k]=f[i-1,j,k]。
⑵第i个人被选中
f[i,j,k]=f[i-1,j-1,k-w[i]]
综上所述,可以得出:
f[i,j,k]=f[i-1,j,k] || f[i-1,j-1,k-w[i]]。

代码

#include<iostream>
#include<cstdio>
#include<cstring> 
#include<cmath>
using namespace std;
int n,a[101],sum;
bool f[51][22510];
void input()
{
	int i;
	memset(f,0,sizeof(f));
	scanf("%d",&n);
	for(sum=0,i=1;i<=n;i++)
	{
		scanf("%d",&a[i]);
		sum+=a[i];//求和
	}
	f[0][0]=1;
	return;
}
void DP()
{
	int i,j,k;
	for(i=1;i<=n;i++)
	{
		for(j=n/2;j>=0;j--)
		{
			for(k=j*450;k>=0;k--)
			{
				if (f[j][k])
					f[j+1][k+a[i]]=1;//状态转移方程
			}
		}
	}
	return;
}
void output()
{
	int i,ans,mn=1000000000;
	for(i=0;i<=sum;i++)//找最小差
		if (f[n/2][i])
		{
			if (abs(i-(sum-i))<mn)
			{
				mn=abs(i-(sum-i));
				ans=i;
			}	
		}
	printf("%d %d",min(ans,sum-ans),max(ans,sum-ans));
	return;
}
int main()
{
	input();
	DP();
	output();
	return 0;
} 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值