题目描述
输入十个数字,五个为一组,分两组,每组里的数字相加,问两组的差最少为多少。例如:
输入10个数字,任意5个求和为a,剩下5个求和为b,问a和b的差的最小是多少。解释
例如1 2 3 4 5 6 7 8 9 10这十个数,1 2 5 9 10为一组和为27,
3 4 6 7 8为另一组和为28,它们的差为1,是最小值。
解题思路
将十个数从小到大排序,
第1、第10,第3、第8、第5分成一组,a[0] a[9] a[2] a[7] a[4]
第2、第 9, 第4、第7、第6分成一组,a[1] a[8] a[3] a[6] a[5]
这样两组数值和之差最小。即可看出规律通用解法:DP问题
有一个没有排序,元素个数为2N的正整数数组。要求把它分割为元素个数为N的两个数组,并使两个子数组的和最接近。
#include <iostream>
#include <algorithm>
using namespace std;
#define MAXN 101
#define MAXSUM 100000
int A[MAXN];
bool dp[MAXN][MAXSUM];
// 题目可转换为从2n个数中选出n个数,其和尽量接近于给定值sum/2
int main()
{
int n, i, k1, k2, s, u;
cin >> n;
//int n=5;
for (i=1; i<=2*n; i++)
cin >> A[i];
int sum = 0;
for (i=1; i<=2*n; i++)
sum += A[i];
memset(dp,0,sizeof(dp));
dp[0][0]=true;
// 对于dp[k][s]要进行u次决策,由于阶段k的选择受到决策的限制,
// 这里决策选择不允许重复,但阶段可以重复,比较特别
for (k1=1; k1<=2*n; k1++)// // 外阶段k1
for (k2=min(k1,n); k2>=1; k2--) // 内阶段k2
for (s=1; s<=sum/2; s++) // 状态s
// 有两个决策包含或不包含元素k1
if (s>=A[k1] && dp[k2-1][s-A[k1]])//判断总和为s的数是否能够等于k2个提取的数之和
dp[k2][s] = true;
// 确定最接近的给定值sum/2的和
for (s=sum/2; s>=1 && !dp[n][s]; s--);
printf("the differece between two sub array is %d\n", sum-2*s);
}