将n个数分为两堆,尽量使每一堆数的和最小。输出和大的那一组的和(相等时输出任意组的和)
如 2 3 4 5 6
4 6 分为一堆,2 3 5分为一堆,则每堆的和为10,达到最小值,输出10
解题思路:
从n个里面选一个数,选一遍,与剩余的数的和作差,取绝对值,当绝对值越小的时候,则保存其中较大和的那一堆数的和。
依次选2个。。。。。。
依次选3个。。。。。。
直到选到n/2个数,因为你选择1个数的时候,相当于你选了剩余n-1个数。这样可以降低时间复杂度。
使用递归。
#include <iostream>
#include <cmath>
using namespace std;
int a[25];
int b[25]; // 标记数组
int n;
int sum = 0;
int ss = 0x3f3f3f;
int ans;
void print_elem(int num){
cout << num << "|" <<sum << "|" << ans <<" ";
for(int i = 0; i < n; i++){
if(b[i] == 1){
cout << a[i] << " ";
}
}
cout << endl;
}
void select_m(int m, int k, int num){ //从n个数里面选取m个数的递归
if(m == 0){
//print_elem(num);
int v = abs(sum-2*num); // a-(sum-a)然两部分的数的绝对值最小
if( ss > v){
ss = v;
if(num > sum-num){
ans = num;
}else{
ans = sum-num;
}
}
return ;
}
for(int i = k; i < n; i++){
b[i] = 1; // 选择第i个数
m --;
num += a[i];
if(i+1 <= n){
select_m(m, i+1, num);
}
num -= a[i];
m ++;
b[i] = 0;
}
}
int main()
{
cin >> n;
for(int i = 0; i < n; i++){
cin >> a[i];
sum += a[i];
}
if(n == 1){
cout << a[0] << endl;
return 0;
}
for(int i = 1; i <= n/2; i++){
select_m(i, 0, 0);
}
cout << ans << endl;
return 0;
}