編程之美 - 數組分割

問題:
有一個沒有排序,有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;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章