[NOIP模拟赛]分钱

题目描述

两个人在街上捡到了一些钱,这些钱共有N张,他们等了很久也没有等来失主,于是决定把钱平分。但钱可能无法平分。他们先把能够平分的钱尽量先平分了,使得剩下不能平分的钱尽量少。这些不能平分的钱怎么办呢他?他们决定拿去赌场里面赌一把。他们运气太好了,那些不能平分的钱变成了双倍,于是他们就把那个钱分了。现在,请问他们每个人带回家多少钱。


输入格式
第一行包含一个整数N(1<=N<=500),表示他们捡到N 张。

接下来N行,每行包含一个正整数ci,表示第i张钱的面值。总金额不超过100000。


输出格式

你输出他们每个人能回家多少钱。


输入样例
5
2
3
5
8

13


输出样例

18


题解:
dp[i][j]:前i张钱分两堆, 两堆差为j时,较大堆的值

#include<cstdio>
#include<cstring>
#define max( a, b ) ( a>b ? a : b )
const int N=505;
const int M=100005;
int n, m[N], dp[N][M], sum;

int main() {
	scanf( "%d", &n );
	for( int i=1; i<=n; i++ ) scanf( "%d", &m[i] ), sum+=m[i];
	memset( dp, -0x3f, sizeof dp ); dp[0][0]=0;
	for( int i=1; i<=n; i++ )
		for( int j=0; j<=(sum>>1); j++ ) {
			dp[i][j]=max( dp[i-1][j], dp[i-1][ j+m[i] ] );//不放or放较小堆, 两堆大小不变
			if( j>=m[i] ) dp[i][j]=max( dp[i][j], dp[i-1][ j-m[i] ]+m[i] );//放较大堆
			if( j<=m[i] ) dp[i][j]=max( dp[i][j], dp[i-1][ m[i]-j ]+j );//放较小堆, 两堆大小交换
		}
	printf( "%d\n", sum-dp[n][0] );
	return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值