问题: 有一个没有排序,有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;
}