题目
给定一个数组nums,将元素分为若干个组,使得每组和相等,求出满足条件的所有分组中,组内元素和的最小值
输入描述: 第一行输入 m 接着输入m个数,表示此数组 数据范围:1<=M<=50, 1<=nums[i]<=50
输出描述:
最小拆分数组和。
示例:
输入:
7 4 3 2 3 5 2 1
输出:
5
说明:可以等分的情况有:
4 个子集(5),(1,4),(2,3),(2,3)
2 个子集(5, 1, 4),(2,3, 2,3)
但最小的为5。
思路
1、对输入数据求和,得到total,然后排序得到排序后的数组vec
2、假设所求子数组最小和为ans,那么total % ans ==0,即能够整除
3、对所有可能的ans遍历,ans初始值为序列最大值,遍历规则如下:
3.1,对vec中的数据由大到小遍历创建flag数组记录当前数据是否已使用,对于vec[i](i初始为m-1),判断vec[i]是否已使用,未使用则在flag数组中标记vec[i]已使用,记录当前以vec[i]为首的子数组和tmpTotal = vec[i],查找vec[i]的一组partners,满足vec[i]与partners的和恰好为ans,即从第0个数到第i- 1个数遍历,对于当前的第j个数,如果满足tmpTotal + vec[j] < ans,则表示vec[j]可成为vec[i]的partner,如果满足tmpTotal + vec[j] == ans则表示vec[i]的partner全部找到。在flag数组中标记vec[j]已使用,接着寻找vec[i - 1]的partner。如果每个数都能找到自己的partners则表示当前的ans就是所求的【等和子数组最小和】否则令ans++,重新开始。
c++代码:
#include <iostream>
#include <string>
#include <map>
#include <set>
#include <vector>
#include <algorithm>
#include <numeric>
using namespace std;
int main()
{
int m = 0;
int ans = 0; //保存最终结果,最小值
int total = 0, tmp = 0;
vector<int> vec;
int bFlag[100] = { false };//记录当前数据是否被使用过
bool bGetAns = true;
cin >> m;
for (int i = 0; i < m; ++i)
{
cin >> tmp;
vec.push_back(tmp);
}
sort(vec.begin(), vec.end());
ans = *max_element(vec.begin(), vec.end());
total = accumulate(vec.begin(), vec.end(), 0);
for (ans; ans < total; ans++)
{
if (total % ans == 0)
{
bGetAns = true;
memset(bFlag, 0, sizeof(bFlag));
for (int i = m - 1; i >= 0; --i)
{
if (bFlag[i])
{
continue;
}
int tmptotal = vec[i];
bFlag[i] = 1;
for (int j = 0; j < i; ++j)
{
if (bFlag[j] == 1)
{
continue;
}
if (tmptotal + vec[j] < ans)
{
tmptotal += vec[j];
bFlag[j] = 1;
}
else if (tmptotal + vec[j] == ans)
{
tmptotal += vec[j];
bFlag[j] = 1;
break;
}
}
if (tmptotal != ans)
{
bGetAns = false;
break;
}
}
if (bGetAns)
{
break;
}
}
}
cout << ans << endl;
return 0;
}