1
0
mirror of https://github.com/danog/Telegram.git synced 2024-12-03 09:57:46 +01:00
Telegram/Telegraph/TGGifKeyboardBalancedPartition.m
2016-02-25 01:03:51 +01:00

117 lines
3.8 KiB
Objective-C

#import "TGGifKeyboardBalancedPartition.h"
#define NH_LP_TABLE_LOOKUP(table, i, j, rowsize) (table)[(i) * (rowsize) + (j)]
@implementation TGGifKeyboardBalancedPartition
+ (NSInteger *)linearPartitionTable:(NSArray *)sequence numPartitions:(NSInteger)numPartitions
{
NSInteger k = numPartitions;
NSInteger n = [sequence count];
// allocate a table buffer of n * k integers
NSInteger tableSize = sizeof(NSInteger) * n * k;
NSInteger *tmpTable = (NSInteger *)malloc(tableSize);
memset(tmpTable, 0, tableSize);
// allocate a solution buffer of (n - 1) * (k - 1) integers
NSInteger solutionSize = sizeof(NSInteger) * (n - 1) * (k - 1);
NSInteger *solution = (NSInteger *)malloc(solutionSize);
memset(solution, 0, solutionSize);
// fill table with initial values
for (NSInteger i = 0; i < n; i++) {
NSInteger offset = i? NH_LP_TABLE_LOOKUP(tmpTable, i - 1, 0, k) : 0;
NH_LP_TABLE_LOOKUP(tmpTable, i, 0, k) = [sequence[i] integerValue] + offset;
}
for (NSInteger j = 0; j < k; j++) {
NH_LP_TABLE_LOOKUP(tmpTable, 0, j, k) = [sequence[0] integerValue];
}
// calculate the costs and fill the solution buffer
for (NSInteger i = 1; i < n; i++) {
for (NSInteger j = 1; j < k; j++) {
NSInteger currentMin = 0;
NSInteger minX = NSIntegerMax;
for (NSInteger x = 0; x < i; x++) {
NSInteger c1 = NH_LP_TABLE_LOOKUP(tmpTable, x, j - 1, k);
NSInteger c2 = NH_LP_TABLE_LOOKUP(tmpTable, i, 0, k) - NH_LP_TABLE_LOOKUP(tmpTable, x, 0, k);
NSInteger cost = MAX(c1, c2);
if (!x || cost < currentMin) {
currentMin = cost;
minX = x;
}
}
NH_LP_TABLE_LOOKUP(tmpTable, i, j, k) = currentMin;
NH_LP_TABLE_LOOKUP(solution, i - 1, j - 1, k - 1) = minX;
}
}
// free the tmp table, we don't need it anymore
free(tmpTable);
return solution;
}
+ (NSArray *)linearPartitionForSequence:(NSArray *)sequence numberOfPartitions:(NSInteger)numberOfPartitions
{
NSInteger n = [sequence count];
NSInteger k = numberOfPartitions;
if (k <= 0) return @[];
if (k >= n) {
NSMutableArray *partition = [[NSMutableArray alloc] init];
[sequence enumerateObjectsUsingBlock:^(id obj, __unused NSUInteger idx, __unused BOOL *stop) {
[partition addObject:@[obj]];
}];
return [partition copy];
}
if (n == 1) {
return @[sequence];
}
// get the solution table
NSInteger *solution = [self linearPartitionTable:sequence numPartitions:numberOfPartitions];
NSInteger solutionRowSize = numberOfPartitions - 1;
k = k - 2;
n = n - 1;
NSMutableArray *answer = [NSMutableArray array];
while (k >= 0) {
if (n < 1) {
[answer insertObject:@[] atIndex:0];
} else {
NSMutableArray *currentAnswer = [NSMutableArray array];
for (NSInteger i = NH_LP_TABLE_LOOKUP(solution, n - 1, k, solutionRowSize) + 1, range = n + 1; i < range; i++) {
[currentAnswer addObject:sequence[i]];
}
[answer insertObject:currentAnswer atIndex:0];
n = NH_LP_TABLE_LOOKUP(solution, n - 1, k, solutionRowSize);
}
k = k - 1;
}
// free the solution table because we don't need it anymore
free(solution);
NSMutableArray *currentAnswer = [NSMutableArray array];
for (NSInteger i = 0, range = n + 1; i < range; i++) {
[currentAnswer addObject:sequence[i]];
}
[answer insertObject:currentAnswer atIndex:0];
return [answer copy];
}
@end