Sage codes

MathJax example

Before pruning - Initial algorithm

(Scroll down for iprovised code)



from itertools import combinations


numbers = [1245, 1675, 2345, 2879, 3456, 6578, 9987, 1092, 665, 
          4567, 7892, 4567]
k = int(input("Enter the number of parts"))

n = len(numbers)


def partitions_of_n(n, k, min_part=1):
    if k == 1:
        if n >= min_part:
            yield (n,)
        return
    for i in range(min_part, n - k + 2):
        for tail in partitions_of_n(n - i, k - 1, i):
            yield (i,) + tail


size_patterns = list(partitions_of_n(n, k))

best_diff = float('inf')
best_partition = None


def generate_groups(remaining, sizes):
    if len(sizes) == 1:
        yield [tuple(remaining)]
        return

    first_size = sizes[0]
    for group in combinations(remaining, first_size):
        new_remaining = list(remaining)
        for x in group:
            new_remaining.remove(x)
        for rest in generate_groups(new_remaining, sizes[1:]):
            yield [group] + rest


for pattern in size_patterns:
    for groups in generate_groups(numbers, pattern):
        sums = [sum(g) for g in groups]
        diff = max(sums) - min(sums)

        if diff < best_diff:
            best_diff = diff
            best_partition = groups


print("Optimal Partition:")
for i, group in enumerate(best_partition, 1):
    print(f"Group {i}: {group}, sum = {sum(group)}")

print("Minimal difference (max-min sum):", best_diff)

Improvised code


from itertools import combinations

numbers = [1245, 1675, 2345, 2879, 3456, 6578, 9987,
           1092, 665, 4567, 7892, 4567]
k = int(input("Enter the number of parts: "))

numbers = sorted(numbers, reverse=True)
n = len(numbers)

best_diff = float('inf')
best_partition = None


def partitions_of_n(n, k, min_part=1):
    if k == 1:
        if n >= min_part:
            yield (n,)
        return
    for i in range(min_part, n - k + 2):
        for tail in partitions_of_n(n - i, k - 1, i):
            yield (i,) + tail


size_patterns = list(partitions_of_n(n, k))


def generate_groups_bb(remaining, sizes, groups, sums, prev_group=None):
    global best_diff, best_partition

    if len(sizes) == 1:
        group = tuple(sorted(remaining))
        groups.append(group)
        sums.append(sum(group))

        diff = max(sums) - min(sums)
        if diff < best_diff:
            best_diff = diff
            best_partition = list(groups)

        groups.pop()
        sums.pop()
        return

    first_size = sizes[0]

    for group in combinations(remaining, first_size):
        group = tuple(sorted(group))

        # Symmetry pruning
        if prev_group is not None and first_size == len(prev_group):
            if group <= prev_group:
                continue

        group_sum = sum(group)

        # Branch-and-bound pruning
        new_sums = sums + [group_sum]
        if len(new_sums) > 1:
            if max(new_sums) - min(new_sums) >= best_diff:
                continue

        new_remaining = list(remaining)
        for x in group:
            new_remaining.remove(x)

        groups.append(group)
        sums.append(group_sum)

        generate_groups_bb(
            new_remaining,
            sizes[1:],
            groups,
            sums,
            group
        )

        groups.pop()
        sums.pop()


for pattern in size_patterns:
    generate_groups_bb(numbers, pattern, [], [], None)


print("\nOptimal Partition:")
for i, group in enumerate(best_partition, 1):
    print(f"Group {i}: {group}, sum = {sum(group)}")

print("Minimal difference (max-min sum):", best_diff)

No comments:

Post a Comment