Phân vùng hợp lý các yếu tố của một danh sách


12

Đưa ra một danh sách xếp hạng người chơi, tôi được yêu cầu phân chia các cầu thủ (tức là xếp hạng) thành hai nhóm một cách công bằng nhất có thể. Mục tiêu là để giảm thiểu sự khác biệt giữa xếp hạng tích lũy của các đội. Không có ràng buộc nào về cách tôi có thể chia các cầu thủ thành các đội (một đội có thể có 2 người chơi và đội còn lại có thể có 10 người chơi).

Ví dụ: [5, 6, 2, 10, 2, 3, 4]nên trả lại([6, 5, 3, 2], [10, 4, 2])

Tôi muốn biết thuật toán để giải quyết vấn đề này. Xin lưu ý rằng tôi đang tham gia một khóa học giới thiệu lập trình trực tuyến, vì vậy các thuật toán đơn giản sẽ được đánh giá cao.

Tôi đang sử dụng mã sau đây, nhưng vì một số lý do, trình kiểm tra mã trực tuyến nói rằng nó không chính xác.

def partition(ratings):
    set1 = []
    set2 =[]
    sum_1 = 0
    sum_2 = 0
    for n in sorted(ratings, reverse=True):
        if sum_1 < sum_2:
            set1.append(n)
            sum_1 = sum_1 + n
        else:
            set2.append(n)
            sum_2 = sum_2 + n
    return(set1, set2)

Cập nhật: Tôi đã liên hệ với các giảng viên và tôi được cho biết nên xác định một chức năng "trợ giúp" khác bên trong chức năng để kiểm tra tất cả các kết hợp khác nhau sau đó tôi cần kiểm tra sự khác biệt tối thiểu.


2
Google "vấn đề tổng hợp con"
John Coleman

@JohnColeman cảm ơn bạn đã gợi ý. Bạn có thể vui lòng hướng dẫn tôi đi đúng hướng về cách sử dụng các tập hợp con để giải quyết vấn đề của tôi không?
EddieEC

6
Thậm chí cụ thể hơn, bạn có một trường hợp đặc biệt của vấn đề tổng hợp con được gọi là vấn đề phân vùng . Bài viết Wikipedia về nó thảo luận về các thuật toán.
John Coleman

4
Điều này có trả lời câu hỏi của bạn không? Chia danh sách thành hai phần bằng nhau thuật toán
kaya3

1
Cảm ơn cả hai người! Tôi chân thành đánh giá cao sự giúp đỡ!
EddieEC

Câu trả lời:


4

Lưu ý: Đã chỉnh sửa để xử lý tốt hơn trường hợp khi tổng của tất cả các số là số lẻ.

Quay lui là một khả năng cho vấn đề này.

Nó cho phép kiểm tra tất cả các khả năng theo cách đệ quy, mà không cần một lượng lớn bộ nhớ.

Nó dừng lại ngay khi tìm thấy giải pháp tối ưu : sum = 0, trong đó sumcó sự khác biệt giữa tổng các phần tử của tập A và tổng các phần tử của tập B. EDIT: nó dừng ngay sum < 2khi xử lý trường hợp khi tổng của tất cả các số là số lẻ, tức là tương ứng với chênh lệch tối thiểu là 1. Nếu tổng toàn cầu này là chẵn, chênh lệch tối thiểu không thể bằng 1.

Nó cho phép thực hiện một thủ tục đơn giản là từ bỏ sớm :
tại một thời điểm nhất định, nếu sumcao hơn thì tổng của tất cả các yếu tố còn lại (nghĩa là không được đặt trong A hoặc B) cộng với giá trị tuyệt đối của mức tối thiểu hiện tại thu được, sau đó chúng ta có thể từ bỏ kiểm tra đường dẫn hiện tại, mà không kiểm tra các yếu tố còn lại. Thủ tục này được tối ưu hóa với:

  • sắp xếp dữ liệu đầu vào theo thứ tự giảm dần
  • Mỗi bước, trước tiên hãy kiểm tra sự lựa chọn có thể xảy ra nhất: điều này cho phép đi nhanh đến một giải pháp gần như tối ưu

Đây là một mã giả

Khởi tạo:

  • sắp xếp các yếu tố a[]
  • Tính tổng các phần tử còn lại: sum_back[i] = sum_back[i+1] + a[i];
  • Đặt "chênh lệch" tối thiểu thành giá trị tối đa của nó: min_diff = sum_back[0];
  • Đặt a[0]trong A -> chỉ số icủa phần tử được kiểm tra được đặt thành 1
  • Đặt up_down = true;: boolean này cho biết nếu chúng ta hiện đang tiến lên (đúng) hoặc lùi (sai)

Trong khi lặp lại:

  • If (up_down): chuyển tiếp

    • Kiểm tra từ bỏ sớm, với sự giúp đỡ của sum_back
    • Chọn giá trị có thể xảy ra nhất, điều chỉnh sumtheo lựa chọn này
    • if (i == n-1): LEAF -> kiểm tra nếu giá trị tối ưu được cải thiện và trả về nếu giá trị mới bằng 0 (EDIT if (... < 2):); đi lạc hậu
    • Nếu không trong một chiếc lá: tiếp tục đi về phía trước
  • If (! Updown): lạc hậu

    • Nếu chúng tôi đến i == 0: trở về
    • Nếu đó là bước thứ hai trong nút này: chọn giá trị thứ hai, đi lên
    • khác: đi xuống
    • Trong cả hai trường hợp: tính toán lại sumgiá trị mới

Đây là một mã, trong C ++ (Xin lỗi, không biết Python)

#include    <iostream>
#include    <vector>
#include    <algorithm>
#include    <tuple>

std::tuple<int, std::vector<int>> partition(std::vector<int> &a) {
    int n = a.size();
    std::vector<int> parti (n, -1);     // current partition studies
    std::vector<int> parti_opt (n, 0);  // optimal partition
    std::vector<int> sum_back (n, 0);   // sum of remaining elements
    std::vector<int> n_poss (n, 0);     // number of possibilities already examined at position i

    sum_back[n-1] = a[n-1];
    for (int i = n-2; i >= 0; --i) {
        sum_back[i] = sum_back[i+1] + a[i];
    }

    std::sort(a.begin(), a.end(), std::greater<int>());
    parti[0] = 0;       // a[0] in A always !
    int sum = a[0];     // current sum

    int i = 1;          // index of the element being examined (we force a[0] to be in A !)
    int min_diff = sum_back[0];
    bool up_down = true;

    while (true) {          // UP
        if (up_down) {
            if (std::abs(sum) > sum_back[i] + min_diff) {  //premature abandon
                i--;
                up_down = false;
                continue;
            }
            n_poss[i] = 1;
            if (sum > 0) {
                sum -= a[i];
                parti[i] = 1;
            } else {
                sum += a[i];
                parti[i] = 0;
            }

            if (i == (n-1)) {           // leaf
                if (std::abs(sum) < min_diff) {
                    min_diff = std::abs(sum);
                    parti_opt = parti;
                    if (min_diff < 2) return std::make_tuple (min_diff, parti_opt);   // EDIT: if (... < 2) instead of (... == 0)
                }
                up_down = false;
                i--;
            } else {
                i++;        
            }

        } else {            // DOWN
            if (i == 0) break;
            if (n_poss[i] == 2) {
                if (parti[i]) sum += a[i];
                else sum -= a[i];
                //parti[i] = 0;
                i--;
            } else {
                n_poss[i] = 2;
                parti[i] = 1 - parti[i];
                if (parti[i]) sum -= 2*a[i];
                else sum += 2*a[i];
                i++;
                up_down = true;
            }
        }
    }
    return std::make_tuple (min_diff, parti_opt);
}

int main () {
    std::vector<int> a = {5, 6, 2, 10, 2, 3, 4, 13, 17, 38, 42};
    int diff;
    std::vector<int> parti;
    std::tie (diff, parti) = partition (a);

    std::cout << "Difference = " << diff << "\n";

    std::cout << "set A: ";
    for (int i = 0; i < a.size(); ++i) {
        if (parti[i] == 0) std::cout << a[i] << " ";
    }
    std::cout << "\n";

    std::cout << "set B: ";
    for (int i = 0; i < a.size(); ++i) {
        if (parti[i] == 1) std::cout << a[i] << " ";
    }
    std::cout << "\n";
}

Vấn đề duy nhất ở đây không phải lúc nào cũng là tổng tối ưu sẽ là 0. Tôi cảm ơn bạn đã giải thích nó khá tốt, vì tôi không thể đọc tốt C ++.
EddieEC

Nếu tổng tối ưu không bằng 0, mã sẽ xem xét tất cả các khả năng, ghi nhớ giải pháp tốt nhất. Các đường dẫn không được kiểm tra là những người chúng tôi chắc chắn rằng chúng không tối ưu. Điều này tương ứng với sự trở lại if I == 0. Tôi đã kiểm tra nó bằng cách thay thế 10 bằng 11 trong ví dụ của bạn
Damien

3

Tôi nghĩ rằng bạn nên tự mình thực hiện bài tập tiếp theo, nếu không bạn không học được nhiều. Đối với điều này, đây là một giải pháp cố gắng thực hiện lời khuyên của người hướng dẫn của bạn:

def partition(ratings):

    def split(lst, bits):
        ret = ([], [])
        for i, item in enumerate(lst):
            ret[(bits >> i) & 1].append(item)
        return ret

    target = sum(ratings) // 2
    best_distance = target
    best_split = ([], [])
    for bits in range(0, 1 << len(ratings)):
        parts = split(ratings, bits)
        distance = abs(sum(parts[0]) - target)
        if best_distance > distance:
            best_distance = distance
            best_split = parts
    return best_split

ratings = [5, 6, 2, 10, 2, 3, 4]
print(ratings)
print(partition(ratings))

Đầu ra:

[5, 6, 2, 10, 2, 3, 4]
([5, 2, 2, 3, 4], [6, 10])

Lưu ý rằng đầu ra này khác với đầu ra mong muốn của bạn, nhưng cả hai đều đúng.

Thuật toán này dựa trên thực tế là, để chọn tất cả các tập hợp con có thể có của một tập hợp nhất định có N phần tử, bạn có thể tạo tất cả các số nguyên với N bit và chọn mục I tùy thuộc vào giá trị của bit thứ I. Tôi để lại cho bạn thêm một vài dòng để dừng ngay khi best_distancesố không (dĩ nhiên vì nó không thể tốt hơn được nữa).

Một bit trên bit (lưu ý đó 0blà tiền tố cho số nhị phân trong Python):

Một số nhị phân: 0b0111001 == 0·2⁶+1·2⁵+1·2⁴+1·2³+0·2²+0·2¹+1·2⁰ == 57

Phải dịch chuyển bởi 1: 0b0111001 >> 1 == 0b011100 == 28

Chuyển sang trái 1: 0b0111001 << 1 == 0b01110010 == 114

Phải dịch chuyển bởi 4: 0b0111001 >> 4 == 0b011 == 3

Bitwise &(và):0b00110 & 0b10101 == 0b00100

Để kiểm tra xem bit thứ 5 (chỉ số 4) có phải là 1 hay không: (0b0111001 >> 4) & 1 == 0b011 & 1 == 1

Một số theo sau là 7 số không: 1 << 7 == 0b10000000

7 cái: (1 << 7) - 1 == 0b10000000 - 1 == 0b1111111

Cả 3-bit kết hợp: 0b000==0, 0b001==1, 0b010==2, 0b011==3, 0b100==4, 0b101==5, 0b110==6, 0b111==7(lưu ý rằng 0b111 + 1 == 0b1000 == 1 << 3)


Cảm ơn bạn rất nhiều! Bạn có thể vui lòng giải thích những gì bạn đã làm? Ngoài ra việc sử dụng << là gì? Những thứ này chẳng hạn tôi chưa bao giờ học cách làm. Nhưng tôi đã biết rằng tôi cần phải tạo ra tất cả các khả năng và trả lại cái có sự khác biệt nhỏ nhất!
EddieEC

Tôi đã thêm một microlesson vào số nhị phân và hoạt động bit
Walter Tross

Bạn có thể không nên xác định một chức năng trong một chức năng khác.
AMC

1
@ AlexanderCécile nó phụ thuộc . Trong trường hợp này, tôi nghĩ rằng nó có thể chấp nhận được và cải thiện sự sạch sẽ, và dù sao, đó là những gì OP đã được đề xuất bởi những người hướng dẫn của anh ấy (xem bản cập nhật trong câu hỏi của anh ấy).
Walter Tross

1
@MiniMax hoán vị của N mục là N!, Nhưng tập con của chúng là 2 ^ N: mục đầu tiên có thể nằm trong tập hợp con hoặc không: 2 khả năng; mục thứ hai có thể nằm trong tập hợp con hoặc không: × 2; mục thứ ba ... và cứ thế, N lần.
Walter Tross

1

Thuật toán sau thực hiện điều này:

  • sắp xếp các mục
  • đưa ngay cả các thành viên vào danh sách a, lẻ trong danh sách bđể bắt đầu
  • di chuyển ngẫu nhiên và hoán đổi các mục giữa abnếu thay đổi là tốt hơn

Tôi đã thêm các câu lệnh in để hiển thị tiến trình trong danh sách ví dụ của bạn:

# -*- coding: utf-8 -*-
"""
Created on Fri Dec  6 18:10:07 2019

@author: Paddy3118
"""

from random import shuffle, random, randint

#%%
items = [5, 6, 2, 10, 2, 3, 4]

def eq(a, b):
    "Equal enough"
    return int(abs(a - b)) == 0

def fair_partition(items, jiggles=100):
    target = sum(items) / 2
    print(f"  Target sum: {target}")
    srt = sorted(items)
    a = srt[::2]    # every even
    b = srt[1::2]   # every odd
    asum = sum(a)
    bsum = sum(b)
    n = 0
    while n < jiggles and not eq(asum, target):
        n += 1
        if random() <0.5:
            # move from a to b?
            if random() <0.5:
                a, b, asum, bsum = b, a, bsum, asum     # Switch
            shuffle(a)
            trial = a[0]
            if abs(target - (bsum + trial)) < abs(target - bsum):  # closer
                b.append(a.pop(0))
                asum -= trial
                bsum += trial
                print(f"  Jiggle {n:2}: Delta after Move: {abs(target - asum)}")
        else:
            # swap between a and b?
            apos = randint(0, len(a) - 1)
            bpos = randint(0, len(b) - 1)
            trya, tryb = a[apos], b[bpos]
            if abs(target - (bsum + trya - tryb)) < abs(target - bsum):  # closer
                b.append(trya)  # adds to end
                b.pop(bpos)     # remove what is swapped
                a.append(tryb)
                a.pop(apos)
                asum += tryb - trya
                bsum += trya - tryb
                print(f"  Jiggle {n:2}: Delta after Swap: {abs(target - asum)}")
    return sorted(a), sorted(b)

if __name__ == '__main__':
    for _ in range(5):           
        print('\nFinal:', fair_partition(items), '\n')  

Đầu ra:

  Target sum: 16.0
  Jiggle  1: Delta after Swap: 2.0
  Jiggle  7: Delta after Swap: 0.0

Final: ([2, 3, 5, 6], [2, 4, 10]) 

  Target sum: 16.0
  Jiggle  4: Delta after Swap: 0.0

Final: ([2, 4, 10], [2, 3, 5, 6]) 

  Target sum: 16.0
  Jiggle  9: Delta after Swap: 3.0
  Jiggle 13: Delta after Move: 2.0
  Jiggle 14: Delta after Swap: 1.0
  Jiggle 21: Delta after Swap: 0.0

Final: ([2, 3, 5, 6], [2, 4, 10]) 

  Target sum: 16.0
  Jiggle  7: Delta after Swap: 3.0
  Jiggle  8: Delta after Move: 1.0
  Jiggle 13: Delta after Swap: 0.0

Final: ([2, 3, 5, 6], [2, 4, 10]) 

  Target sum: 16.0
  Jiggle  5: Delta after Swap: 0.0

Final: ([2, 4, 10], [2, 3, 5, 6]) 

Cảm ơn bạn rất nhiều, nhưng tôi phải làm điều đó mà không cần nhập bất cứ điều gì.
EddieEC

1

Vì tôi biết tôi phải tạo tất cả các danh sách có thể, tôi cần tạo một hàm "trợ giúp" để giúp tạo ra tất cả các khả năng. Sau khi làm điều đó, tôi đúng để kiểm tra sự khác biệt tối thiểu và sự kết hợp các danh sách với sự khác biệt tối thiểu đó là giải pháp mong muốn.

Hàm trợ giúp là đệ quy và kiểm tra tất cả các khả năng kết hợp danh sách.

def partition(ratings):

    def helper(ratings, left, right, aux_list, current_index):
        if current_index >= len(ratings):
            aux_list.append((left, right))
            return

        first = ratings[current_index]
        helper(ratings, left + [first], right, aux_list, current_index + 1)
        helper(ratings, left, right + [first], aux_list, current_index + 1)

    #l contains all possible sublists
    l = []
    helper(ratings, [], [], l, 0)
    set1 = []
    set2 = []
    #set mindiff to a large number
    mindiff = 1000
    for sets in l:
        diff = abs(sum(sets[0]) - sum(sets[1]))
        if diff < mindiff:
            mindiff = diff
            set1 = sets[0]
            set2 = sets[1]
    return (set1, set2)

Ví dụ : r = [1, 2, 2, 3, 5, 4, 2, 4, 5, 5, 2], phân vùng tối ưu sẽ là: ([1, 2, 2, 3, 5, 4], [2, 4, 5, 5, 2])với sự khác biệt là 1.

r = [73, 7, 44, 21, 43, 42, 92, 88, 82, 70], phân vùng tối ưu sẽ là: ([73, 7, 21, 92, 88], [44, 43, 42, 82, 70])với sự khác biệt của 0.


1
kể từ khi bạn hỏi tôi: giải pháp của bạn là tốt nếu bạn đang học. Nó chỉ có một vấn đề mà bạn may mắn không gặp phải trước vấn đề khác mà nó có chung với các giải pháp khác: nó sử dụng không gian theo cấp số nhân (O (n2ⁿ)). Nhưng thời gian theo cấp số nhân là một vấn đề từ lâu. Tuy nhiên, tránh sử dụng không gian theo cấp số nhân sẽ dễ dàng.
Walter Tross

1

Dưới đây là một ví dụ khá công phu, dành cho mục đích giáo dục hơn là hiệu suất. Nó giới thiệu một số khái niệm Python thú vị như hiểu danh sách và trình tạo, cũng như một ví dụ tốt về đệ quy trong đó các trường hợp rìa cần phải được kiểm tra một cách thích hợp. Các tiện ích mở rộng, ví dụ: chỉ các đội có số lượng người chơi bằng nhau là hợp lệ, dễ dàng thực hiện trong các chức năng riêng lẻ phù hợp.

def listFairestWeakTeams(ratings):
    current_best_weak_team_rating = -1
    fairest_weak_teams = []
    for weak_team in recursiveWeakTeamGenerator(ratings):
        weak_team_rating = teamRating(weak_team, ratings)
        if weak_team_rating > current_best_weak_team_rating:
            fairest_weak_teams = []
            current_best_weak_team_rating = weak_team_rating
        if weak_team_rating == current_best_weak_team_rating:
            fairest_weak_teams.append(weak_team)
    return fairest_weak_teams


def recursiveWeakTeamGenerator(
    ratings,
    weak_team=[],
    current_applicant_index=0
):
    if not isValidWeakTeam(weak_team, ratings):
        return
    if current_applicant_index == len(ratings):
        yield weak_team
        return
    for new_team in recursiveWeakTeamGenerator(
        ratings,
        weak_team + [current_applicant_index],
        current_applicant_index + 1
    ):
        yield new_team
    for new_team in recursiveWeakTeamGenerator(
        ratings,
        weak_team,
        current_applicant_index + 1
    ):
        yield new_team


def isValidWeakTeam(weak_team, ratings):
    total_rating = sum(ratings)
    weak_team_rating = teamRating(weak_team, ratings)
    optimal_weak_team_rating = total_rating // 2
    if weak_team_rating > optimal_weak_team_rating:
        return False
    elif weak_team_rating * 2 == total_rating:
        # In case of equal strengths, player 0 is assumed
        # to be in the "weak" team
        return 0 in weak_team
    else:
        return True


def teamRating(team_members, ratings):
    return sum(memberRatings(team_members, ratings))    


def memberRatings(team_members, ratings):
    return [ratings[i] for i in team_members]


def getOpposingTeam(team, ratings):
    return [i for i in range(len(ratings)) if i not in team]


ratings = [5, 6, 2, 10, 2, 3, 4]
print("Player ratings:     ", ratings)
print("*" * 40)
for option, weak_team in enumerate(listFairestWeakTeams(ratings)):
    strong_team = getOpposingTeam(weak_team, ratings)
    print("Possible partition", option + 1)
    print("Weak team members:  ", weak_team)
    print("Weak team ratings:  ", memberRatings(weak_team, ratings))
    print("Strong team members:", strong_team)
    print("Strong team ratings:", memberRatings(strong_team, ratings))
    print("*" * 40)

Đầu ra:

Player ratings:      [5, 6, 2, 10, 2, 3, 4]
****************************************
Possible partition 1
Weak team members:   [0, 1, 2, 5]
Weak team ratings:   [5, 6, 2, 3]
Strong team members: [3, 4, 6]
Strong team ratings: [10, 2, 4]
****************************************
Possible partition 2
Weak team members:   [0, 1, 4, 5]
Weak team ratings:   [5, 6, 2, 3]
Strong team members: [2, 3, 6]
Strong team ratings: [2, 10, 4]
****************************************
Possible partition 3
Weak team members:   [0, 2, 4, 5, 6]
Weak team ratings:   [5, 2, 2, 3, 4]
Strong team members: [1, 3]
Strong team ratings: [6, 10]
****************************************

1

Cho rằng bạn muốn thậm chí các đội bạn biết điểm số của xếp hạng của mỗi đội. Đây là tổng của xếp hạng chia cho 2.

Vì vậy, đoạn mã sau nên làm những gì bạn muốn.

from itertools import combinations

ratings = [5, 6, 2, 10, 2, 3, 4]

target = sum(ratings)/2 

difference_dictionary = {}
for i in range(1, len(ratings)): 
    for combination in combinations(ratings, i): 
        diff = sum(combination) - target
        if diff >= 0: 
            difference_dictionary[diff] = difference_dictionary.get(diff, []) + [combination]

# get min difference to target score 
min_difference_to_target = min(difference_dictionary.keys())
strong_ratings = difference_dictionary[min_difference_to_target]
first_strong_ratings = [x for x in strong_ratings[0]]

weak_ratings = ratings.copy()
for strong_rating in first_strong_ratings: 
    weak_ratings.remove(strong_rating)

Đầu ra

first_strong_ratings 
[6, 10]

weak_rating 
[5, 2, 2, 3, 4]

Có những phân chia khác có cùng fairnessnhững thứ này đều có sẵn trong bộ dữ liệu mạnh_ratings, tôi chỉ chọn xem cái đầu tiên vì nó sẽ luôn tồn tại cho bất kỳ danh sách xếp hạng nào mà bạn vượt qua (được cung cấp len(ratings) > 1).


Thách thức của câu hỏi này là không nhập bất cứ thứ gì như tôi đã đề cập trong câu hỏi của mình. Cảm ơn về thông tin bạn vừa nhập!
EddieEC

0

Một giải pháp tham lam có thể mang lại một giải pháp tối ưu phụ. Đây là một giải pháp tham lam khá đơn giản, ý tưởng là sắp xếp danh sách theo thứ tự giảm dần để giảm hiệu quả của việc thêm xếp hạng trong nhóm. Xếp hạng sẽ được thêm vào nhóm đó có tổng số xếp hạng ít hơn

lis = [5, 6, 2, 10, 2, 3, 4]
lis.sort()
lis.reverse()

bucket_1 = []
bucket_2 = []

for item in lis:
    if sum(bucket_1) <= sum(bucket_2):
        bucket_1.append(item)
    else:
        bucket_2.append(item)

print("Bucket 1 : {}".format(bucket_1))
print("Bucket 2 : {}".format(bucket_2))

Đầu ra:

Bucket 1 : [10, 4, 2]
Bucket 2 : [6, 5, 3, 2]

Biên tập:

Một cách tiếp cận khác sẽ là tạo ra tất cả các tập hợp con có thể có của danh sách. Giả sử bạn có l1 là một trong những tập hợp con của danh sách, sau đó bạn có thể dễ dàng lấy danh sách l2 sao cho l2 = list (bản gốc) - l1. Số của tất cả các tập hợp con có thể có của danh sách kích thước n là 2 ^ n. Chúng ta có thể biểu thị chúng là seq của một số nguyên từ 0 đến 2 ^ n -1. Lấy một ví dụ, giả sử bạn có danh sách = [1, 3, 5] thì không có kết hợp nào có thể là 2 ^ 3 tức là 8. Bây giờ chúng ta có thể viết tất cả kết hợp như sau:

  1. 000 - [] - 0
  2. 001 - [1] - 1
  3. 010 - [3] - 2
  4. 011 - [1,3] - 3
  5. 100 - [5] - 4
  6. 101 - [1,5] - 5
  7. 110 - [3,5] - 6
  8. 111 - [1,3,5] - 7 và l2, trong trường hợp này, có thể dễ dàng thu được bằng cách lấy xor với 2 ^ n-1.

Giải pháp:

def sum_list(lis, n, X):
    """
    This function will return sum of all elemenst whose bit is set to 1 in X
    """
    sum_ = 0
    # print(X)
    for i in range(n):
        if (X & 1<<i ) !=0:
            # print( lis[i], end=" ")
            sum_ += lis[i]
    # print()
    return sum_

def return_list(lis, n, X):
    """
    This function will return list of all element whose bit is set to 1 in X
    """
    new_lis = []
    for i in range(n):
        if (X & 1<<i) != 0:
            new_lis.append(lis[i])
    return new_lis

lis = [5, 6, 2, 10, 2, 3, 4]
n = len(lis)
total = 2**n -1 

result_1 = 0
result_2 = total
result_1_sum = 0
result_2_sum = sum_list(lis,n, result_2)
ans = total
for i in range(total):
    x = (total ^ i)
    sum_x = sum_list(lis, n, x)
    sum_y = sum_list(lis, n, i)

    if abs(sum_x-sum_y) < ans:
        result_1 =  x
        result_2 = i
        result_1_sum = sum_x
        result_2_sum = sum_y
        ans = abs(result_1_sum-result_2_sum)

"""
Produce resultant list
"""

bucket_1 = return_list(lis,n,result_1)
bucket_2 = return_list(lis, n, result_2)

print("Bucket 1 : {}".format(bucket_1))
print("Bucket 2 : {}".format(bucket_2))

Đầu ra:

Bucket 1 : [5, 2, 2, 3, 4]
Bucket 2 : [6, 10]

Xin chào, nếu bạn đọc câu hỏi ban đầu của tôi, bạn có thể thấy tôi đã sử dụng Phương pháp Tham lam và nó đã bị từ chối. Cảm ơn bạn cho đầu vào của bạn mặc dù!
EddieEC

@EddieEC ràng buộc về n (độ dài của mảng) là gì. Nếu bạn muốn tạo tất cả các kết hợp có thể thì về cơ bản đó là một vấn đề tổng hợp con, đó là một vấn đề hoàn chỉnh NP.
vkSinha
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.