题目连接:
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 <stdio.h>
#include <iostream>
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;
}