[NOIP模拟赛]分钱

题目描述

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


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

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


输出格式

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


输入样例
5
2
3
5
8

13


输出样例

18


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

#include
#include
#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;
}

你可能感兴趣的:(考试,动态规划)