TOJ 2378


题目连接:

http://acm.tzc.edu.cn/acmhome/problemdetail.do?&method=showdetail&id=2378


题目类型:

动态规划 - 01背包


数据结构:

// 重量 人数 
int dp[25005][105];


思路分析:

---------------------------------------------------------------------------------------

本题原意为均分问题,

将所有人分为两队,要求每队人数相差不能超过1, 要求体重相差最小.

将其转换为01背包问题,

既然人数相差不能大于1, 则吧人数 除以2, 若人数是奇数, 则 加一后除以2

得到一半的人数n

同理,将所有体重之和除以2

得到一半的总体重m

问题转换为 要求达到n人( 或 n-1 人 总人数是奇数的情况 )

体重尽量靠近m

因为一旦一只队伍体重尽可能的靠近 m

则另一半也会越来越接近 m,


所以只要生成一个二维背包问题即可

最终答案dp[m][n] ( 或者 dp[m][n - 1] ) 哪个更接近m 就是答案


证明:


源代码:

#include 
#include 
using namespace std;

// 重量 人数 
int dp[25005][105];

int _abs( int a )
{
	return a < 0 ? -1 * a : a;
}

int main()
{
	int i, j, k, n, m, l;
	int arr[105];
	
	while( scanf( "%d", &n ) != EOF )
	{
		for (i = 0; i <= 25001; i++)
		{
			for (j = 0; j <= 101; j++)
			{
				if( j )
				{
					dp[i][j] = -999999;
				}
				else
				{
					dp[i][j] = 0;
				}
			}
		}
		
		int snt = 0;
		
		for( i = 1; i <= n; i ++ )
		{
			scanf( "%d", &arr[i] );
			snt += arr[i];
		}
		
		l = snt % 2 == 0 ? snt / 2 : ( snt + 1 ) / 2;
		m = n % 2 == 0 ? n / 2 : ( n + 1 ) / 2;
	
		for( i = 1; i <= n; i ++ )
		{
			for( j = l; j >= arr[i]; j -- )
			{
				for( k = m; k >= 1; k -- )
				{
					if( dp[j][k] < dp[j - arr[i]][k - 1] + arr[i] )
					{
						dp[j][k] = dp[j - arr[i]][k - 1] + arr[i];
					}
				}
			}
		}
		
		int rlt = _abs( snt - 2 * dp[l][m] ) < _abs( snt - 2 * dp[l][m - 1] ) ? dp[l][m] : dp[l][m - 1];
		
		if( rlt <= 0 )
		{
			printf( "%d %d\n", 0, snt );
		}
		else
		{
			if( rlt > snt - rlt )
			{
				printf( "%d %d\n", snt - rlt, rlt );
			}
			else
			{
				printf( "%d %d\n", rlt, snt - rlt );
			}
		}
	}
	
	return 0;
}



你可能感兴趣的:(ACM解题报告)