Code organization
main()
does everything. It would be a good idea to separate the concerns, such that main()
is responsible for I/O and for calling a function that determines the optimal partition.
Variables
int n, *arr, onee = 0, twoo, threee, total = 0, maxx = -1, temp_maxx;
Those are some weird variable names! If you have some sticky keys on your keyboard, you should clean out the residue.
new int[n];
If you call new
, there should be a corresponding delete[]
. Better, you could use a variable-length array or a std::vector<int>
.
Data representation
A useful observation to make is that you don't need to store the individual numbers. Rather, the running total is more useful. The benefit is that you can find the sum of any subarray in constant time. That is, instead of storing
2, 80, 50, 42, 1, 1, 1, 2
you should store
2, 82, 132, 174, 175, 176, 177, 179
You could always reconstruct the original list from the running totals (not that you need to do so to solve this problem).
The only concern would be overflow. You didn't specify any length or size constraints on your problem, though, so I'm not going to worry about it.
Algorithm
I suggest the following strategy:
- Tentatively place the right split past the end of the array, and find the optimal left split. (Given the cumulative representation, partitioning an array optimally into two is easy — O(log n) using a binary search for half of the total.)
- Move the right split to the left, and adjust the left split as necessary. (The optimal left split can only ever move left, if at all.)
The complexity of the algorithm is O(n).
#include <algorithm>
#include <iostream>
#include <iterator>
template <typename T>
T max(const T a, const T b, const T c) {
return std::max(a, std::max(b, c));
}
/**
* Given an array represented as cumulative sums, find a split
* that produces the most equal left and right sums.
*/
template <typename ConstIter>
ConstIter minimaxPartition2(ConstIter begin, ConstIter end) {
typedef typename std::iterator_traits<ConstIter>::value_type T;
if (end - begin <= 1) {
return end;
}
T total = *(end - 1);
T ideal = total / 2;
ConstIter split = std::upper_bound(begin, end, ideal);
T aSum = std::max(*(split - 1), total - *(split - 1));
T bSum = std::max(*split, total - *split);
return aSum < bSum ? split - 1 : split;
}
/**
* Given an array represented as cumulative sums, find a split
* that produces the most equal left and right sums by considering
* small leftward movements of the upperEstimate split point.
*/
template <typename ConstIter>
ConstIter minimaxPartition2(ConstIter begin, ConstIter end, ConstIter upperEstimate) {
typedef typename std::iterator_traits<ConstIter>::value_type T;
const T total = *(end - 1);
ConstIter bestSplit = upperEstimate;
T bestSum = std::max(*(bestSplit - 1), total - *(bestSplit - 1));
for (ConstIter split = bestSplit - 1; split >= begin; --split) {
T sum = std::max(*(split - 1), total - *(split - 1));
if (sum < bestSum) {
bestSum = sum;
bestSplit = split;
} else {
break;
}
}
return bestSplit;
}
template <typename ConstIter>
typename std::iterator_traits<ConstIter>::value_type
minimaxPartition3(ConstIter begin, ConstIter end) {
typedef typename std::iterator_traits<ConstIter>::value_type T;
const T total = *(end - 1);
ConstIter split2 = end,
split1 = minimaxPartition2(begin, split2);
T leftSum = *split1,
rightSum = 0,
best = max(leftSum, total - leftSum - rightSum, rightSum);
while (--split2 > split1 && rightSum < best) {
rightSum = total - *split2;
split1 = minimaxPartition2(begin, split2, split1);
leftSum = *split1;
best = std::min(best, max(leftSum, total - leftSum - rightSum, rightSum));
}
return best;
}
int main() {
size_t len;
std::cin >> len;
long cumulative[len];
for (int sum = 0, i = 0; i < len; sum = cumulative[i++]) {
long n;
std::cin >> n;
if (n <= 0) {
return 1;
}
cumulative[i] = sum + n;
}
std::cout << minimaxPartition3(cumulative, cumulative + len) << std::endl;
return 0;
}