Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> Python

Python: หา Subset ทุกชุดที่มีผลรวมเท่ากับค่าที่กำหนด

บทนำ

โจทย์ Subset Sum Problem คือการหาชุดย่อย (subset) ทุกชุดจากลิสต์ที่มีผลรวมเท่ากับค่าเป้าหมาย s สามารถแก้ได้ด้วยการสร้างคอมบิเนชันทุกความยาวแล้วตรวจสอบผลรวม

วิธีการ: ใช้ itertools.combinations

โมดูล itertools มีฟังก์ชัน combinations() ที่สร้างคอมบิเนชันทุกชุดได้อย่างมีประสิทธิภาพ

ตัวอย่างโค้ด

from itertools import combinations

def subset_sum(arr, target):
    """คืนลิสต์ของ subset ทุกชุดที่มีผลรวมเท่ากับ target"""
    result = []
    n = len(arr)
    # ลองทุกความยาวของ subset ตั้งแต่ 0 ถึง n
    for r in range(n + 1):
        for combo in combinations(arr, r):
            if sum(combo) == target:
                result.append(list(combo))
    return result

# ทดสอบ
my_list = [21, 32, 56, 78, 45, 99, 0]
target = 53

print(f"ลิสต์ต้นทาง: {my_list}")
print(f"ค่าเป้าหมาย: {target}")
print("Subset ที่มีผลรวมเท่ากับเป้าหมาย:")

subsets = subset_sum(my_list, target)
for subset in subsets:
    print(f"  {subset} -> sum = {sum(subset)}")

ผลลัพธ์

ลิสต์ต้นทาง: [21, 32, 56, 78, 45, 99, 0]
ค่าเป้าหมาย: 53
Subset ที่มีผลรวมเท่ากับเป้าหมาย:
  [21, 32] -> sum = 53
  [21, 32, 0] -> sum = 53

บันทึกประสิทธิภาพ

  • ความซับซ้อนเวลา: O(2^n) - เหมาะกับลิสต์ขนาดเล็ก (n ≤ 20)
  • สำหรับลิสต์ใหญ่ ควรใช้ Dynamic Programming หรือ Meet-in-the-Middle
  • หากมีค่าลบในลิสต์ จำนวน subset อาจมากมาย

วิธีปรับปรุงประสิทธิภาพ (Pruning)

def subset_sum_optimized(arr, target):
    """เวอร์ชันที่เร็วกว่าด้วยการ sort และ pruning"""
    arr = sorted(arr)
    result = []
    
    def backtrack(start, path, current_sum):
        if current_sum == target:
            result.append(path[:])
            return
        if current_sum > target:
            return
        for i in range(start, len(arr)):
            # ข้ามค่าซ้ำเพื่อไม่ให้ subset ซ้ำ
            if i > start and arr[i] == arr[i-1]:
                continue
            path.append(arr[i])
            backtrack(i + 1, path, current_sum + arr[i])
            path.pop()
    
    backtrack(0, [], 0)
    return result

สรุป

วิธี itertools.combinations เข้าใจง่ายและเขียนสั้น เหมาะสำหรับข้อมูลเล็กและการเรียนรู้ สำหรับระบบจริงที่ต้องการประสิทธิภาพ ควรใช้ backtracking พร้อม pruning หรือ Dynamic Programming