题目大意:有一堆各种面值的硬币,将所有硬币分成两堆,使得两堆的总值之差尽可能小。
开始看到题目竟然很久都找不出状态和状态转移方程,几天没做题脑袋就生锈了。
申请一个dp【50001】来记录该币值能否取得,可以当成0-1背包做。然后从sum/2开始往下遍历,直到第一个标记为1的币值结束,再算一下即可。
#include <iostream>
#include <cstdio>
#include <string.h>
#include <cmath>
#include <algorithm>
using namespace std;
bool dp[50001];
int coin[101];
int n,sum;
int main()
{
int t,i,j;
scanf("%d",&t);
while( t--)
{
scanf("%d",&n);
sum =0;
for( i=0; i<n; i++)
{
scanf("%d",&coin[i]);
sum+= coin[i];
}
memset( dp,0, sizeof( dp));
//将所有能够取到的数字标记出来
dp[0]=1;
for( i=0; i<n; i++)
for( j=sum; j>=coin[i]; j--)
if( !dp[j]) dp[j] =dp[j-coin[i]];
for( i=sum/2; i>=0;i--)
if( dp[i])
{
printf("%d\n",sum-i-i);
break;
}
}
return 0;
}