import itertools
def find_smallest_covering_subsets( tables, target_numbers_list) :
"""
Determines the smallest subset(s) of tables that contain all specified numbers.
Args:
tables (dict): A dictionary where keys are table names (e.g., "IMAGE1")
and values are the 2D list representations of the tables.
target_numbers_list (list): A list of numbers that the subset must contain.
Returns:
list: A list of tuples, where each tuple represents one of the smallest
subsets of table names that covers all target numbers. Returns an
empty list if no subset can cover all numbers.
"""
target_numbers_set = set ( target_numbers_list)
# Step 1: Pre-process to find which target numbers each table contains.
# We create a set of all unique, non-zero numbers for each table.
table_contents = { }
for name, table_data in tables.items ( ) :
# Flatten the 2D list into a 1D list and convert to a set
# The number 0 is treated as a placeholder and ignored.
unique_numbers = { num for row in table_data for num in row if num != 0 }
table_contents[ name] = unique_numbers
# Find the coverage of target numbers for each table
table_coverage = { }
for name, numbers in table_contents.items ( ) :
table_coverage[ name] = numbers.intersection ( target_numbers_set)
# Step 2: Iterate through subset sizes from 1 up to the total number of tables.
# We stop as soon as we find the first set of solutions, ensuring they are the smallest.
table_names = list ( tables.keys ( ) )
for size in range ( 1 , len ( table_names) + 1 ) :
smallest_subsets = [ ]
# Generate all combinations of tables for the current size
for subset_candidate in itertools .combinations ( table_names, size) :
# Step 3: Check if the current combination covers all target numbers.
combined_coverage = set ( )
for table_name in subset_candidate:
combined_coverage.update ( table_coverage[ table_name] )
# If the union of numbers in the subset matches the target set, it's a solution.
if combined_coverage == target_numbers_set:
smallest_subsets.append ( subset_candidate)
# If we found any solutions at this size, they must be the smallest.
# Return them and do not check larger subset sizes.
if smallest_subsets:
return smallest_subsets
# If the loop completes without finding a solution, return an empty list.
return [ ]
# --- Data Definition ---
IMAGE1 = [
[ 1 , 0 , 0 , 56 , 0 , 29 , 44 , 0 ] ,
[ 31 , 0 , 0 , 42 , 0 , 3 , 54 , 0 ] ,
[ 0 , 8 , 49 , 0 , 28 , 0 , 0 , 45 ] ,
[ 0 , 26 , 47 , 0 , 6 , 0 , 0 , 51 ] ,
[ 0 , 37 , 20 , 0 , 57 , 0 , 0 , 16 ] ,
[ 0 , 59 , 14 , 0 , 39 , 0 , 0 , 18 ] ,
[ 36 , 0 , 0 , 21 , 0 , 64 , 9 , 0 ] ,
[ 62 , 0 , 0 , 11 , 0 , 34 , 23 , 0 ]
]
IMAGE2 = [
[ 49 , 15 , 0 , 0 , 20 , 46 , 0 , 0 ] ,
[ 0 , 0 , 2 , 64 , 0 , 0 , 35 , 29 ] ,
[ 0 , 0 , 39 , 25 , 0 , 0 , 6 , 60 ] ,
[ 24 , 42 , 0 , 0 , 53 , 11 , 0 , 0 ] ,
[ 45 , 19 , 0 , 0 , 16 , 50 , 0 , 0 ] ,
[ 0 , 0 , 30 , 36 , 0 , 0 , 63 , 1 ] ,
[ 0 , 0 , 59 , 5 , 0 , 0 , 26 , 40 ] ,
[ 12 , 54 , 0 , 0 , 41 , 23 , 0 , 0 ]
]
IMAGE3 = [
[ 10 , 0 , 47 , 0 , 0 , 50 , 0 , 23 ] ,
[ 0 , 32 , 0 , 57 , 40 , 0 , 1 , 0 ] ,
[ 54 , 0 , 19 , 0 , 0 , 14 , 0 , 43 ] ,
[ 0 , 36 , 0 , 5 , 28 , 0 , 61 , 0 ] ,
[ 15 , 0 , 42 , 0 , 0 , 55 , 0 , 18 ] ,
[ 0 , 25 , 0 , 64 , 33 , 0 , 8 , 0 ] ,
[ 51 , 0 , 22 , 0 , 0 , 11 , 0 , 46 ] ,
[ 0 , 37 , 0 , 4 , 29 , 0 , 60 , 0 ]
]
IMAGE4 = [
[ 1 , 32 , 0 , 0 , 0 , 0 , 49 , 48 ] ,
[ 56 , 41 , 0 , 0 , 0 , 0 , 8 , 25 ] ,
[ 0 , 0 , 4 , 29 , 52 , 45 , 0 , 0 ] ,
[ 0 , 0 , 53 , 44 , 5 , 28 , 0 , 0 ] ,
[ 16 , 17 , 0 , 0 , 0 , 0 , 64 , 33 ] ,
[ 57 , 40 , 0 , 0 , 0 , 0 , 9 , 24 ] ,
[ 0 , 0 , 13 , 20 , 61 , 36 , 0 , 0 ] ,
[ 0 , 0 , 60 , 37 , 12 , 21 , 0 , 0 ]
]
IMAGE5 = [
[ 7 , 0 , 61 , 0 , 34 , 0 , 28 , 0 ] ,
[ 0 , 1 , 0 , 59 , 0 , 40 , 0 , 30 ] ,
[ 42 , 0 , 20 , 0 , 15 , 0 , 53 , 0 ] ,
[ 0 , 48 , 0 , 22 , 0 , 9 , 0 , 51 ] ,
[ 0 , 25 , 0 , 35 , 0 , 64 , 0 , 6 ] ,
[ 31 , 0 , 37 , 0 , 58 , 0 , 4 , 0 ] ,
[ 0 , 56 , 0 , 14 , 0 , 17 , 0 , 43 ] ,
[ 50 , 0 , 12 , 0 , 23 , 0 , 45 , 0 ]
]
IMAGE6 = [
[ 16 , 0 , 0 , 37 , 20 , 0 , 0 , 57 ] ,
[ 51 , 0 , 0 , 26 , 47 , 0 , 0 , 6 ] ,
[ 13 , 0 , 0 , 40 , 17 , 0 , 0 , 60 ] ,
[ 50 , 0 , 0 , 27 , 46 , 0 , 0 , 7 ] ,
[ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ] ,
[ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ] ,
[ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ] ,
[ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ]
]
# --- Main Execution ---
if __name__ == "__main__" :
# The dictionary of all tables
all_tables = {
"IMAGE1" : IMAGE1,
"IMAGE2" : IMAGE2,
"IMAGE3" : IMAGE3,
"IMAGE4" : IMAGE4,
"IMAGE5" : IMAGE5,
"IMAGE6" : IMAGE6,
}
# The sequence of numbers to be found
target_sequence = [ 18 , 7 , 9 , 16 , 20 , 5 , 4 , 21 , 15 , 10 , 6 , 19 , 17 , 8 , 1 , 3 , 22 , 14 , 2 , 23 , 13 , 12 , 24 , 25 ]
# Find and print the results
solutions = find_smallest_covering_subsets( all_tables, target_sequence)
if solutions:
min_size = len ( solutions[ 0 ] )
print ( f"The smallest subset size required to find all numbers is: {min_size}\n " )
print ( "The following subset(s) of tables contain all the numbers:" )
for i, subset in enumerate ( solutions, 1 ) :
print ( f" Solution {i}: {', '.join(subset)}" )
else :
print ( "No subset of the given tables contains all the required numbers." )
aW1wb3J0IGl0ZXJ0b29scwoKZGVmIGZpbmRfc21hbGxlc3RfY292ZXJpbmdfc3Vic2V0cyh0YWJsZXMsIHRhcmdldF9udW1iZXJzX2xpc3QpOgogICAgIiIiCiAgICBEZXRlcm1pbmVzIHRoZSBzbWFsbGVzdCBzdWJzZXQocykgb2YgdGFibGVzIHRoYXQgY29udGFpbiBhbGwgc3BlY2lmaWVkIG51bWJlcnMuCgogICAgQXJnczoKICAgICAgICB0YWJsZXMgKGRpY3QpOiBBIGRpY3Rpb25hcnkgd2hlcmUga2V5cyBhcmUgdGFibGUgbmFtZXMgKGUuZy4sICJJTUFHRTEiKQogICAgICAgICAgICAgICAgICAgICAgIGFuZCB2YWx1ZXMgYXJlIHRoZSAyRCBsaXN0IHJlcHJlc2VudGF0aW9ucyBvZiB0aGUgdGFibGVzLgogICAgICAgIHRhcmdldF9udW1iZXJzX2xpc3QgKGxpc3QpOiBBIGxpc3Qgb2YgbnVtYmVycyB0aGF0IHRoZSBzdWJzZXQgbXVzdCBjb250YWluLgoKICAgIFJldHVybnM6CiAgICAgICAgbGlzdDogQSBsaXN0IG9mIHR1cGxlcywgd2hlcmUgZWFjaCB0dXBsZSByZXByZXNlbnRzIG9uZSBvZiB0aGUgc21hbGxlc3QKICAgICAgICAgICAgICBzdWJzZXRzIG9mIHRhYmxlIG5hbWVzIHRoYXQgY292ZXJzIGFsbCB0YXJnZXQgbnVtYmVycy4gUmV0dXJucyBhbgogICAgICAgICAgICAgIGVtcHR5IGxpc3QgaWYgbm8gc3Vic2V0IGNhbiBjb3ZlciBhbGwgbnVtYmVycy4KICAgICIiIgogICAgdGFyZ2V0X251bWJlcnNfc2V0ID0gc2V0KHRhcmdldF9udW1iZXJzX2xpc3QpCgogICAgIyBTdGVwIDE6IFByZS1wcm9jZXNzIHRvIGZpbmQgd2hpY2ggdGFyZ2V0IG51bWJlcnMgZWFjaCB0YWJsZSBjb250YWlucy4KICAgICMgV2UgY3JlYXRlIGEgc2V0IG9mIGFsbCB1bmlxdWUsIG5vbi16ZXJvIG51bWJlcnMgZm9yIGVhY2ggdGFibGUuCiAgICB0YWJsZV9jb250ZW50cyA9IHt9CiAgICBmb3IgbmFtZSwgdGFibGVfZGF0YSBpbiB0YWJsZXMuaXRlbXMoKToKICAgICAgICAjIEZsYXR0ZW4gdGhlIDJEIGxpc3QgaW50byBhIDFEIGxpc3QgYW5kIGNvbnZlcnQgdG8gYSBzZXQKICAgICAgICAjIFRoZSBudW1iZXIgMCBpcyB0cmVhdGVkIGFzIGEgcGxhY2Vob2xkZXIgYW5kIGlnbm9yZWQuCiAgICAgICAgdW5pcXVlX251bWJlcnMgPSB7bnVtIGZvciByb3cgaW4gdGFibGVfZGF0YSBmb3IgbnVtIGluIHJvdyBpZiBudW0gIT0gMH0KICAgICAgICB0YWJsZV9jb250ZW50c1tuYW1lXSA9IHVuaXF1ZV9udW1iZXJzCgogICAgIyBGaW5kIHRoZSBjb3ZlcmFnZSBvZiB0YXJnZXQgbnVtYmVycyBmb3IgZWFjaCB0YWJsZQogICAgdGFibGVfY292ZXJhZ2UgPSB7fQogICAgZm9yIG5hbWUsIG51bWJlcnMgaW4gdGFibGVfY29udGVudHMuaXRlbXMoKToKICAgICAgICB0YWJsZV9jb3ZlcmFnZVtuYW1lXSA9IG51bWJlcnMuaW50ZXJzZWN0aW9uKHRhcmdldF9udW1iZXJzX3NldCkKCiAgICAjIFN0ZXAgMjogSXRlcmF0ZSB0aHJvdWdoIHN1YnNldCBzaXplcyBmcm9tIDEgdXAgdG8gdGhlIHRvdGFsIG51bWJlciBvZiB0YWJsZXMuCiAgICAjIFdlIHN0b3AgYXMgc29vbiBhcyB3ZSBmaW5kIHRoZSBmaXJzdCBzZXQgb2Ygc29sdXRpb25zLCBlbnN1cmluZyB0aGV5IGFyZSB0aGUgc21hbGxlc3QuCiAgICB0YWJsZV9uYW1lcyA9IGxpc3QodGFibGVzLmtleXMoKSkKICAgIGZvciBzaXplIGluIHJhbmdlKDEsIGxlbih0YWJsZV9uYW1lcykgKyAxKToKICAgICAgICBzbWFsbGVzdF9zdWJzZXRzID0gW10KICAgICAgICAjIEdlbmVyYXRlIGFsbCBjb21iaW5hdGlvbnMgb2YgdGFibGVzIGZvciB0aGUgY3VycmVudCBzaXplCiAgICAgICAgZm9yIHN1YnNldF9jYW5kaWRhdGUgaW4gaXRlcnRvb2xzLmNvbWJpbmF0aW9ucyh0YWJsZV9uYW1lcywgc2l6ZSk6CiAgICAgICAgICAgIAogICAgICAgICAgICAjIFN0ZXAgMzogQ2hlY2sgaWYgdGhlIGN1cnJlbnQgY29tYmluYXRpb24gY292ZXJzIGFsbCB0YXJnZXQgbnVtYmVycy4KICAgICAgICAgICAgY29tYmluZWRfY292ZXJhZ2UgPSBzZXQoKQogICAgICAgICAgICBmb3IgdGFibGVfbmFtZSBpbiBzdWJzZXRfY2FuZGlkYXRlOgogICAgICAgICAgICAgICAgY29tYmluZWRfY292ZXJhZ2UudXBkYXRlKHRhYmxlX2NvdmVyYWdlW3RhYmxlX25hbWVdKQogICAgICAgICAgICAKICAgICAgICAgICAgIyBJZiB0aGUgdW5pb24gb2YgbnVtYmVycyBpbiB0aGUgc3Vic2V0IG1hdGNoZXMgdGhlIHRhcmdldCBzZXQsIGl0J3MgYSBzb2x1dGlvbi4KICAgICAgICAgICAgaWYgY29tYmluZWRfY292ZXJhZ2UgPT0gdGFyZ2V0X251bWJlcnNfc2V0OgogICAgICAgICAgICAgICAgc21hbGxlc3Rfc3Vic2V0cy5hcHBlbmQoc3Vic2V0X2NhbmRpZGF0ZSkKICAgICAgICAKICAgICAgICAjIElmIHdlIGZvdW5kIGFueSBzb2x1dGlvbnMgYXQgdGhpcyBzaXplLCB0aGV5IG11c3QgYmUgdGhlIHNtYWxsZXN0LgogICAgICAgICMgUmV0dXJuIHRoZW0gYW5kIGRvIG5vdCBjaGVjayBsYXJnZXIgc3Vic2V0IHNpemVzLgogICAgICAgIGlmIHNtYWxsZXN0X3N1YnNldHM6CiAgICAgICAgICAgIHJldHVybiBzbWFsbGVzdF9zdWJzZXRzCiAgICAgICAgICAgIAogICAgIyBJZiB0aGUgbG9vcCBjb21wbGV0ZXMgd2l0aG91dCBmaW5kaW5nIGEgc29sdXRpb24sIHJldHVybiBhbiBlbXB0eSBsaXN0LgogICAgcmV0dXJuIFtdCgojIC0tLSBEYXRhIERlZmluaXRpb24gLS0tCgpJTUFHRTEgPSBbCiAgICBbIDEsICAwLCAgMCwgNTYsICAwLCAyOSwgNDQsICAwXSwKICAgIFszMSwgIDAsICAwLCA0MiwgIDAsICAzLCA1NCwgIDBdLAogICAgWyAwLCAgOCwgNDksICAwLCAyOCwgIDAsICAwLCA0NV0sCiAgICBbIDAsIDI2LCA0NywgIDAsICA2LCAgMCwgIDAsIDUxXSwKICAgIFsgMCwgMzcsIDIwLCAgMCwgNTcsICAwLCAgMCwgMTZdLAogICAgWyAwLCA1OSwgMTQsICAwLCAzOSwgIDAsICAwLCAxOF0sCiAgICBbMzYsICAwLCAgMCwgMjEsICAwLCA2NCwgIDksICAwXSwKICAgIFs2MiwgIDAsICAwLCAxMSwgIDAsIDM0LCAyMywgIDBdCl0KCklNQUdFMiA9IFsKICAgIFs0OSwgMTUsICAwLCAgMCwgMjAsIDQ2LCAgMCwgIDBdLAogICAgWyAwLCAgMCwgIDIsIDY0LCAgMCwgIDAsIDM1LCAyOV0sCiAgICBbIDAsICAwLCAzOSwgMjUsICAwLCAgMCwgIDYsIDYwXSwKICAgIFsyNCwgNDIsICAwLCAgMCwgNTMsIDExLCAgMCwgIDBdLAogICAgWzQ1LCAxOSwgIDAsICAwLCAxNiwgNTAsICAwLCAgMF0sCiAgICBbIDAsICAwLCAzMCwgMzYsICAwLCAgMCwgNjMsICAxXSwKICAgIFsgMCwgIDAsIDU5LCAgNSwgIDAsICAwLCAyNiwgNDBdLAogICAgWzEyLCA1NCwgIDAsICAwLCA0MSwgMjMsICAwLCAgMF0KXQoKSU1BR0UzID0gWwogICAgWzEwLCAgMCwgNDcsICAwLCAgMCwgNTAsICAwLCAyM10sCiAgICBbIDAsIDMyLCAgMCwgNTcsIDQwLCAgMCwgIDEsICAwXSwKICAgIFs1NCwgIDAsIDE5LCAgMCwgIDAsIDE0LCAgMCwgNDNdLAogICAgWyAwLCAzNiwgIDAsICA1LCAyOCwgIDAsIDYxLCAgMF0sCiAgICBbMTUsICAwLCA0MiwgIDAsICAwLCA1NSwgIDAsIDE4XSwKICAgIFsgMCwgMjUsICAwLCA2NCwgMzMsICAwLCAgOCwgIDBdLAogICAgWzUxLCAgMCwgMjIsICAwLCAgMCwgMTEsICAwLCA0Nl0sCiAgICBbIDAsIDM3LCAgMCwgIDQsIDI5LCAgMCwgNjAsICAwXQpdCgpJTUFHRTQgPSBbCiAgICBbIDEsIDMyLCAgMCwgIDAsICAwLCAgMCwgNDksIDQ4XSwKICAgIFs1NiwgNDEsICAwLCAgMCwgIDAsICAwLCAgOCwgMjVdLAogICAgWyAwLCAgMCwgIDQsIDI5LCA1MiwgNDUsICAwLCAgMF0sCiAgICBbIDAsICAwLCA1MywgNDQsICA1LCAyOCwgIDAsICAwXSwKICAgIFsxNiwgMTcsICAwLCAgMCwgIDAsICAwLCA2NCwgMzNdLAogICAgWzU3LCA0MCwgIDAsICAwLCAgMCwgIDAsICA5LCAyNF0sCiAgICBbIDAsICAwLCAxMywgMjAsIDYxLCAzNiwgIDAsICAwXSwKICAgIFsgMCwgIDAsIDYwLCAzNywgMTIsIDIxLCAgMCwgIDBdCl0KCklNQUdFNSA9IFsKICAgIFsgNywgIDAsIDYxLCAgMCwgMzQsICAwLCAyOCwgIDBdLAogICAgWyAwLCAgMSwgIDAsIDU5LCAgMCwgNDAsICAwLCAzMF0sCiAgICBbNDIsICAwLCAyMCwgIDAsIDE1LCAgMCwgNTMsICAwXSwKICAgIFsgMCwgNDgsICAwLCAyMiwgIDAsICA5LCAgMCwgNTFdLAogICAgWyAwLCAyNSwgIDAsIDM1LCAgMCwgNjQsICAwLCAgNl0sCiAgICBbMzEsICAwLCAzNywgIDAsIDU4LCAgMCwgIDQsICAwXSwKICAgIFsgMCwgNTYsICAwLCAxNCwgIDAsIDE3LCAgMCwgNDNdLAogICAgWzUwLCAgMCwgMTIsICAwLCAyMywgIDAsIDQ1LCAgMF0KXQoKSU1BR0U2ID0gWwogICAgWzE2LCAgMCwgIDAsIDM3LCAyMCwgIDAsICAwLCA1N10sCiAgICBbNTEsICAwLCAgMCwgMjYsIDQ3LCAgMCwgIDAsICA2XSwKICAgIFsxMywgIDAsICAwLCA0MCwgMTcsICAwLCAgMCwgNjBdLAogICAgWzUwLCAgMCwgIDAsIDI3LCA0NiwgIDAsICAwLCAgN10sCiAgICBbIDAsICAwLCAgMCwgIDAsICAwLCAgMCwgIDAsICAwXSwKICAgIFsgMCwgIDAsICAwLCAgMCwgIDAsICAwLCAgMCwgIDBdLAogICAgWyAwLCAgMCwgIDAsICAwLCAgMCwgIDAsICAwLCAgMF0sCiAgICBbIDAsICAwLCAgMCwgIDAsICAwLCAgMCwgIDAsICAwXQpdCgojIC0tLSBNYWluIEV4ZWN1dGlvbiAtLS0KCmlmIF9fbmFtZV9fID09ICJfX21haW5fXyI6CiAgICAjIFRoZSBkaWN0aW9uYXJ5IG9mIGFsbCB0YWJsZXMKICAgIGFsbF90YWJsZXMgPSB7CiAgICAgICAgIklNQUdFMSI6IElNQUdFMSwKICAgICAgICAiSU1BR0UyIjogSU1BR0UyLAogICAgICAgICJJTUFHRTMiOiBJTUFHRTMsCiAgICAgICAgIklNQUdFNCI6IElNQUdFNCwKICAgICAgICAiSU1BR0U1IjogSU1BR0U1LAogICAgICAgICJJTUFHRTYiOiBJTUFHRTYsCiAgICB9CgogICAgIyBUaGUgc2VxdWVuY2Ugb2YgbnVtYmVycyB0byBiZSBmb3VuZAogICAgdGFyZ2V0X3NlcXVlbmNlID0gWzE4LCA3LCA5LCAxNiwgMjAsIDUsIDQsIDIxLCAxNSwgMTAsIDYsIDE5LCAxNywgOCwgMSwgMywgMjIsIDE0LCAyLCAyMywgMTMsIDEyLCAyNCwgMjVdCgogICAgIyBGaW5kIGFuZCBwcmludCB0aGUgcmVzdWx0cwogICAgc29sdXRpb25zID0gZmluZF9zbWFsbGVzdF9jb3ZlcmluZ19zdWJzZXRzKGFsbF90YWJsZXMsIHRhcmdldF9zZXF1ZW5jZSkKCiAgICBpZiBzb2x1dGlvbnM6CiAgICAgICAgbWluX3NpemUgPSBsZW4oc29sdXRpb25zWzBdKQogICAgICAgIHByaW50KGYiVGhlIHNtYWxsZXN0IHN1YnNldCBzaXplIHJlcXVpcmVkIHRvIGZpbmQgYWxsIG51bWJlcnMgaXM6IHttaW5fc2l6ZX1cbiIpCiAgICAgICAgcHJpbnQoIlRoZSBmb2xsb3dpbmcgc3Vic2V0KHMpIG9mIHRhYmxlcyBjb250YWluIGFsbCB0aGUgbnVtYmVyczoiKQogICAgICAgIGZvciBpLCBzdWJzZXQgaW4gZW51bWVyYXRlKHNvbHV0aW9ucywgMSk6CiAgICAgICAgICAgIHByaW50KGYiICBTb2x1dGlvbiB7aX06IHsnLCAnLmpvaW4oc3Vic2V0KX0iKQogICAgZWxzZToKICAgICAgICBwcmludCgiTm8gc3Vic2V0IG9mIHRoZSBnaXZlbiB0YWJsZXMgY29udGFpbnMgYWxsIHRoZSByZXF1aXJlZCBudW1iZXJzLiIpCgo=