算法题解:将n个数分为两堆,尽量使每一堆数的和最小。输出和大的那一组的和(相等时输出任意组的和)

将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;
}

posted @ 2020-12-14 14:15  没尾巴的刺刺鱼  阅读(367)  评论(0编辑  收藏  举报