版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/WUDAIJUN/article/details/8700504
// 数组分割.cpp : 定义控制台应用程序的入口点。
//
//问题描述:将一个有2N个元素的数组分为两个元素个数为N的子数组,要求两子数组的和最接近
//思路:《编程之美》P202 用动态规划得到2N个元素中任意N个元素能得到的所有和。再找出其中最接近sum/2的一个 设为x
// 最后再通过一个动态规划算法找出和为x且个数为N的子数组
#include "stdafx.h"
#include <iostream>
using namespace std;
#include<vector>
int GetHalfSum(int arr[], const int size);
void FindAndPrintSubArr(int arr[], const int size, int AimSum, int curIndex = 0);
int _tmain(int argc, _TCHAR* argv[])
{
int arr[10] = {1, 5, 7, 8, 9, 6, 3, 11, 20, 17};
int halfsum = GetHalfSum(arr, 10);
cout<<"halfsum = "<<halfsum<<endl;
FindAndPrintSubArr(arr, 10, halfsum);
getchar();
getchar();
return 0;
}
int GetHalfSum(int arr[], int size)
{
//求得原数组元素之和
int sum = 0;
for (int i=0; i<size; i++)
sum += arr[i];
//求得arr[0...k]中任意i个元素能组成的元素和 随着k增大逐渐扩展
//最终将arr中任意i个元素能组成的和保存在vecSumSet[i]中
vector<vector<int>> vecSumSet(size/2+1);
vecSumSet.at(0).push_back(0);
for (int k=0; k<size; k++)
{
int i_max = min(k-1, size/2-1);
for (int i=0; i <= i_max; i++)
{
vector<int>::iterator iter = vecSumSet.at(i).begin();
for( ; iter != vecSumSet.at(i).end(); iter++)
vecSumSet.at(i+1).push_back(*iter + arr[k]);
}
}
//将vecSumSet[size/2]中的元素取出,逐个与sum/2对比 找出最接近sum/2的size/2个元素的和
vector<int>::iterator iter = vecSumSet.at(size/2).begin();
int minDiff = sum;
int bestSum;
for (; iter != vecSumSet.at(size/2).end(); iter++)
{
int tempDiff = abs(*iter-sum/2);
if (tempDiff < minDiff)
{
minDiff = tempDiff;
bestSum = *iter;
}
}
return bestSum;
}
//在arr中找出元素个数为size/2且元素和为AimSum的子数组 并输出它和剩余的子数组
void FindAndPrintSubArr(int arr[], const int size, int AimSum, int curIndex)
{
static vector<int> subArr;
static int iSchemeNum = 0;
if (curIndex >= size)
return;
//同时满足元素和为AimSum且元素个数为size/2(这里==size/2-1,因为还没算arr[curIndex])
if (arr[curIndex] == AimSum && subArr.size() == size/2-1)
{
subArr.push_back(arr[curIndex]);
//先输出subArr中的数据
cout<<"方案 "<<++iSchemeNum<<" : "<<endl;
vector<int>::iterator iter = subArr.begin();
for ( ; iter!=subArr.end(); iter++)
cout<<" "<<*iter;
cout<<" \t与 ";
//输出arr中剩余的数据
iter = subArr.begin();
for (int i=0; i<size; i++)
{
if (iter == subArr.end() || arr[i] != *iter)
cout<<" "<<arr[i];
else
iter++;
}
cout<<endl;
subArr.pop_back();
}
//递归左右子树
if (arr[curIndex] < AimSum)
{
subArr.push_back(arr[curIndex]);
FindAndPrintSubArr(arr, size, AimSum-arr[curIndex], curIndex+1);
subArr.pop_back();
}
FindAndPrintSubArr(arr, size, AimSum, curIndex+1);
}