编程之美 - 数组分割

问题: 有一个没有排序,有2N个元素的数组,要求把这个数组分为两部分,分别含有N个元素,并使两个子数组的和最接近。 这里的程序主要是计算这个和的值。

比如数组 {
1, 10, 100, 1000
},计算后符合的分法是 {1, 1000} {10, 100} 和算出比较小的就可以了是  110 例如数组 {1, 2, 3, 4}  分开后是 {1, 4} 和 {2, 3}

思考方法:

动态规划 1)  计算出数组中所有元素的和,并把它除以2,这样得到了目标值。 2)  但目标值不一定是能达到的,比如 数组 {1, 10, 100, 1000} 目标值是 1111/2=555,但最后的分解结果只能是 110 和 1001。      算法会尝试从1到目标值,检查是否他们每一个是否可以被数组元素组合出来,从而找到最接近目标值的和,找到最优解。      fun_1 和 fun_2

这种算法的缺点是如果和很大效率就不高了,尤其当和很大,但数组中元素的个数又比较少的时候,用起来就不是很适合了。

#include <iostream>
#include <vector>

using namespace std;

int getSum(int* arr, int len, int start)
{
    int sum = 0, i = 0;
    for (i = start; i <= len; i++)
    {
        sum += arr[i];
    }
    return sum;
}

int min(int a, int b)
{
    return (a < b)? a:b;
}

int max(int a, int b)
{
    return (a > b)? a:b;
}

void print_bool_arr(bool** arr, int X, int Y)
{
    int i =0, j = 0;
    for (i = 0; i < X; i++)
    {
        for (j = 0; j < Y; j++)
        {
            if (arr[i][j])
                cout << "1  ";
            else
                cout << "0  ";
        }
        cout << endl;
    }
    cout << endl << endl;
}

void print_int_arr(int** arr, int X, int Y)
{
    int i =0, j = 0;
    for (i = 0; i < X; i++)
    {
        for (j = 0; j < Y; j++)
        {
            cout << arr[i][j] << "  ";
        }
        cout << endl;
    }
    cout << endl << endl;
}

int fun_1(int* arr, int N)
{
    int i , j , s;
    int sum = 0;
    bool **isOK;

    sum = getSum(arr, N*2, 1);

    isOK = new bool*[2*N+1];
    for (i = 0; i < N*2+1; i++)
    {
        isOK[i] = new bool[sum/2+2];
        memset(isOK[i], 0, sum/2+2);
    }
    isOK[0][0] = true;

    print_bool_arr(isOK, 2*N+1, sum/2+2);
    for(i = 1 ; i <= 2*N ; ++i)
    {
        for( j = 1 ; j <= min(i,N) ; ++j)
        {
            cout << "i=" << i << "  j=" << j << endl;

            for(s = sum/2 ; s >= arr[i] ; --s)
            {
                if ((isOK[j-1][s-arr[i]]) && ((s-arr[i]) != arr[i]))
                    isOK[j][s] = true;
            }
            print_bool_arr(isOK, 2*N+1, sum/2+2);
        }
    }
    s = 0;
    for (s = sum/2+1; s >= 0; --s)
    {
        if (isOK[N][s])
        {
            cout << "sum " << s << endl;
            break;
        }
    }

    for (i = 0; i < N*2+1; i++)
    {
        delete[] isOK[i];
        isOK[i] = NULL;
    }
    delete[] isOK;
    isOK = NULL;

    return s;
}


int fun_2(int *arr, int N)
{
    int i=0, j=0, s=0;
    int **result;
    int sum = 0;

    sum = getSum(arr, N*2, 1);
    result = new int*[N*2+1];
    for (i = 0; i < N*2+1; i++)
    {
        result[i] = new int[sum/2+2];
        memset(result[i], 0, sizeof(int)*(sum/2+2));
    }

    print_int_arr(result, N*2+1, sum/2+2);
    for (i = 1; i <= 2*N; i++)
    {
        for (j = 1; j <= min(i, N); j++)
        {
            for (s=sum/2; s >= arr[i]; s--)
            {
                if (((j-1) == 0) && (s-arr[i] == 0))
                {
                    result[j][s] = max(result[j-1][s-arr[i]]+arr[i], result[j][s]);
                }
                else
                {
                    if (((result[j-1][s-arr[i]] != 0) && (s-arr[i]) != arr[i]))
                    {
                        result[j][s] = max(result[j-1][s-arr[i]]+arr[i], result[j][s]);
                    }
                }
            }
            print_int_arr(result, N*2+1, sum/2+2);
        }
    }
    s = 0;
    for (s = sum/2+1; s >= 0; --s)
    {
        if (result[N][s])
        {
            cout << "sum " << s << endl;
            break;
        }
    }
    for (i = 0; i < N*2+1; i++)
    {
        delete[] result[i];
        result[i] = NULL;
    }
    delete[] result;
    result = NULL;

    return s;
}

void main()
{
    int i;
    //int test[] = {0, 3, 2, 1, 4};
    //int test[] = {0, 1, 2, 3, 50};
    //int test[] = {0, 1, 10, 100, 1000};
    int test[] = {0, 1, 5, 6, 4, 7, 2, 3, 8};
    //int test[] = {0, 1, 20, 6, 4, 7, 2, 3, 21};


    int len = sizeof(test)/sizeof(test[0]);

    fun_1(test, (len-1)/2);
    //fun_2(test, (len-1)/2);
    cin >> i;
}
    原文作者:zy__
    原文地址: https://blog.csdn.net/wangzhiyu1980/article/details/51812192
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞