एसएटी-सॉल्वर (पायथन) के साथ एक विशिष्ट क्षेत्र के भीतर मुफ्त पॉलीमिनो के सभी संयोजनों का पता लगाना


15

मैं सैट सॉल्वरों की दुनिया में नया हूं और निम्नलिखित समस्या के बारे में कुछ मार्गदर्शन की आवश्यकता होगी।

उस पर विचार करना:

❶ मेरे पास 4 * 4 ग्रिड में 14 आसन्न कोशिकाओं का चयन है

❷ मैं 5 है polyominoes आकार 4, 2, 5, 2 और 1 के (ए, बी, सी, डी, ई)

❸ ये पॉलीओमीनो मुक्त होते हैं , अर्थात इनका आकार निश्चित नहीं होता है और ये विभिन्न पैटर्न बना सकते हैं

यहां छवि विवरण दर्ज करें

मैं एसएटी-सॉल्वर के साथ चयनित क्षेत्र (ग्रे में सेल) के अंदर इन 5 मुक्त पॉलीमिनोइन के सभी संभावित संयोजनों की गणना कैसे कर सकता हूं ?

@ स्पिंकस के आनंददायक उत्तर और OR- टूल डॉक्यूमेंटेशन दोनों से उधार लेकर मैं निम्नलिखित उदाहरण कोड (ज्यूपिटर नोटबुक में चलाता है) बना सकता हूं:

from ortools.sat.python import cp_model

import numpy as np
import more_itertools as mit
import matplotlib.pyplot as plt
%matplotlib inline


W, H = 4, 4 #Dimensions of grid
sizes = (4, 2, 5, 2, 1) #Size of each polyomino
labels = np.arange(len(sizes))  #Label of each polyomino

colors = ('#FA5454', '#21D3B6', '#3384FA', '#FFD256', '#62ECFA')
cdict = dict(zip(labels, colors)) #Color dictionary for plotting

inactiveCells = (0, 1) #Indices of disabled cells (in 1D)
activeCells = set(np.arange(W*H)).difference(inactiveCells) #Cells where polyominoes can be fitted
ranges = [(next(g), list(g)[-1]) for g in mit.consecutive_groups(activeCells)] #All intervals in the stack of active cells



def main():
    model = cp_model.CpModel()


    #Create an Int var for each cell of each polyomino constrained to be within Width and Height of grid.
    pminos = [[] for s in sizes]
    for idx, s in enumerate(sizes):
        for i in range(s):
            pminos[idx].append([model.NewIntVar(0, W-1, 'p%i'%idx + 'c%i'%i + 'x'), model.NewIntVar(0, H-1, 'p%i'%idx + 'c%i'%i + 'y')])



    #Define the shapes by constraining the cells relative to each other

    ## 1st polyomino -> tetromino ##
    #                              #      
    #                              # 
    #            #                 # 
    #           ###                # 
    #                              # 
    ################################

    p0 = pminos[0]
    model.Add(p0[1][0] == p0[0][0] + 1) #'x' of 2nd cell == 'x' of 1st cell + 1
    model.Add(p0[2][0] == p0[1][0] + 1) #'x' of 3rd cell == 'x' of 2nd cell + 1
    model.Add(p0[3][0] == p0[0][0] + 1) #'x' of 4th cell == 'x' of 1st cell + 1

    model.Add(p0[1][1] == p0[0][1]) #'y' of 2nd cell = 'y' of 1st cell
    model.Add(p0[2][1] == p0[1][1]) #'y' of 3rd cell = 'y' of 2nd cell
    model.Add(p0[3][1] == p0[1][1] - 1) #'y' of 3rd cell = 'y' of 2nd cell - 1



    ## 2nd polyomino -> domino ##
    #                           #      
    #                           # 
    #           #               # 
    #           #               # 
    #                           # 
    #############################

    p1 = pminos[1]
    model.Add(p1[1][0] == p1[0][0])
    model.Add(p1[1][1] == p1[0][1] + 1)



    ## 3rd polyomino -> pentomino ##
    #                              #      
    #            ##                # 
    #            ##                # 
    #            #                 # 
    #                              #
    ################################

    p2 = pminos[2]
    model.Add(p2[1][0] == p2[0][0] + 1)
    model.Add(p2[2][0] == p2[0][0])
    model.Add(p2[3][0] == p2[0][0] + 1)
    model.Add(p2[4][0] == p2[0][0])

    model.Add(p2[1][1] == p2[0][1])
    model.Add(p2[2][1] == p2[0][1] + 1)
    model.Add(p2[3][1] == p2[0][1] + 1)
    model.Add(p2[4][1] == p2[0][1] + 2)



    ## 4th polyomino -> domino ##
    #                           #      
    #                           # 
    #           #               #   
    #           #               # 
    #                           # 
    #############################

    p3 = pminos[3]
    model.Add(p3[1][0] == p3[0][0])
    model.Add(p3[1][1] == p3[0][1] + 1)



    ## 5th polyomino -> monomino ##
    #                             #      
    #                             # 
    #           #                 # 
    #                             # 
    #                             # 
    ###############################
    #No constraints because 1 cell only



    #No blocks can overlap:
    block_addresses = []
    n = 0
    for p in pminos:
        for c in p:
            n += 1
            block_address = model.NewIntVarFromDomain(cp_model.Domain.FromIntervals(ranges),'%i' % n)
                model.Add(c[0] + c[1] * W == block_address)
                block_addresses.append(block_address)

    model.AddAllDifferent(block_addresses)



    #Solve and print solutions as we find them
    solver = cp_model.CpSolver()

    solution_printer = SolutionPrinter(pminos)
    status = solver.SearchForAllSolutions(model, solution_printer)

    print('Status = %s' % solver.StatusName(status))
    print('Number of solutions found: %i' % solution_printer.count)




class SolutionPrinter(cp_model.CpSolverSolutionCallback):
    ''' Print a solution. '''

    def __init__(self, variables):
        cp_model.CpSolverSolutionCallback.__init__(self)
        self.variables = variables
        self.count = 0

    def on_solution_callback(self):
        self.count += 1


        plt.figure(figsize = (2, 2))
        plt.grid(True)
        plt.axis([0,W,H,0])
        plt.yticks(np.arange(0, H, 1.0))
        plt.xticks(np.arange(0, W, 1.0))


        for i, p in enumerate(self.variables):
            for c in p:
                x = self.Value(c[0])
                y = self.Value(c[1])
                rect = plt.Rectangle((x, y), 1, 1, fc = cdict[i])
                plt.gca().add_patch(rect)

        for i in inactiveCells:
            x = i%W
            y = i//W
            rect = plt.Rectangle((x, y), 1, 1, fc = 'None', hatch = '///')
            plt.gca().add_patch(rect)

यहां छवि विवरण दर्ज करें

समस्या यह है कि मेरे पास हार्ड-कोडेड 5 अद्वितीय / फिक्स्ड पॉलीओमिनोइज़ हैं और मुझे नहीं पता कि बाधाओं को कैसे परिभाषित किया जाए ताकि प्रत्येक पॉलीमिनो के लिए प्रत्येक संभव पैटर्न को ध्यान में रखा जाए (बशर्ते यह संभव हो)।


मैंने पहली बार Google OR-tools के बारे में सुना है। यह इस तरह के रूप में मानक पायथन पुस्तकालयों का उपयोग करना संभव है itertools, numpy, networkx?
मैथ्यूक्स

मैं एक सॉल-सॉल्वर का उपयोग करना पसंद करूंगा, या उपकरण को अधिमानतः।
solub

@solub मिनीज़िंक भाषा का उपयोग करके इस तरह की समस्या को हल करना / हल करना बहुत आसान है, क्योंकि एक सतह पर अनियमित वस्तुओं को रखने के लिए उच्च-स्तरीय बाधाएं हैं। यदि आप कौरसेरा पर मुफ्त कोर्स "एडवांस्ड मॉडलिंग फॉर डिस्क्रीट ऑप्टिमाइजेशन" के माध्यम से चलते हैं, तो आपको वास्तव में यह सिखाया जाएगा कि इसे कैसे किया जाए और कुछ व्यावहारिक (और अधिक जटिल) उदाहरण दिए जाएं। Or-Tools में MiniZinc भाषा के लिए एक इंटरफ़ेस है, जिससे आप अभी भी इसकी शक्ति का उपयोग कर इसका त्वरित समाधान पा सकते हैं।
पैट्रिक ट्रेंटिन

1
दिलचस्प लगता है, सूचक के लिए धन्यवाद। निश्चित नहीं है कि यह उस विशिष्ट समस्या का उत्तर देगा जो मेरे पास है (मुक्त पॉलीमिनोइज़ को शामिल करने में अड़चन को परिभाषित करते हुए, स्थिर नहीं) लेकिन मैं निश्चित रूप से इस पर एक नज़र डालूंगा।
solub

1
मुझे माफी मांगनी चाहिए, मैं इस प्रश्न के बारे में पूरी तरह से भूल गया था। एक हुई है संबंधित सवाल में minizincएक विस्तृत जवाब यह है कि उपयोग के बारे में मेरे पिछले सुझाव को शामिल किया गया साथ टैग minizinc
पैट्रिक ट्रेंटिन

जवाबों:


10

संपादित करें: मैंने मूल उत्तर में "मुक्त" शब्द को याद किया और तय पॉलीओमीनो के लिए OR-Tools का उपयोग करके उत्तर दिया। नि: शुल्क पॉलीओमीनो के समाधान को शामिल करने के लिए उत्तर देने के लिए एक खंड जोड़ा गया - जो AFAICT OR-Tools के साथ कसना प्रोग्रामिंग में सटीक रूप से व्यक्त करने के लिए काफी मुश्किल है।

OR-TOOLS के साथ फिक्स्ड पॉलिमर:

हाँ, आप इसे OR-Tools में बाधा प्रोग्रामिंग के साथ कर सकते हैं । OR-Tools को 2D ग्रिड ज्यामिति के बारे में कुछ भी नहीं पता है, इसलिए आपको स्थितिगत बाधाओं के संदर्भ में आपके पास प्रत्येक आकार की ज्यामिति को एनकोड करना होगा। Ie एक आकृति ब्लॉक / कोशिकाओं का एक संग्रह है जो एक दूसरे से एक निश्चित संबंध होना चाहिए, ग्रिड की सीमा के भीतर होना चाहिए और ओवरलैप नहीं होना चाहिए। एक बार जब आपके पास अपना बाधा मॉडल होता है तो आप सीपी-सैट सॉल्वर से इसे हल करने के लिए कहते हैं, आपके मामले में, सभी संभावित समाधानों के लिए।

यहाँ एक 4x4 ग्रिड पर दो आयत आकृतियों के साथ अवधारणा का एक बहुत ही सरल प्रमाण है (आप बड़े पैमाने पर समस्या में OR- उपकरण चर और बाधाओं के एक सेट में आकार विवरण से जाने के लिए किसी प्रकार का दुभाषिया कोड जोड़ना चाहेंगे। चूंकि हाथ से बाधाओं को इनपुट करना थकाऊ है)।

from ortools.sat.python import cp_model

(W, H) = (3, 3) # Width and height of our grid.
(X, Y) = (0, 1) # Convenience constants.


def main():
  model = cp_model.CpModel()
  # Create an Int var for each block of each shape constrained to be within width and height of grid.
  shapes = [
    [
      [ model.NewIntVar(0, W, 's1b1_x'), model.NewIntVar(0, H, 's1b1_y') ],
      [ model.NewIntVar(0, W, 's1b2_x'), model.NewIntVar(0, H, 's1b2_y') ],
      [ model.NewIntVar(0, W, 's1b3_x'), model.NewIntVar(0, H, 's1b3_y') ],
    ],
    [
      [ model.NewIntVar(0, W, 's2b1_x'), model.NewIntVar(0, H, 's2b1_y') ],
      [ model.NewIntVar(0, W, 's2b2_x'), model.NewIntVar(0, H, 's2b2_y') ],
    ]
  ]

  # Define the shapes by constraining the blocks relative to each other.
  # 3x1 rectangle:
  s0 = shapes[0]
  model.Add(s0[0][Y] == s0[1][Y])
  model.Add(s0[0][Y] == s0[2][Y])
  model.Add(s0[0][X] == s0[1][X] - 1)
  model.Add(s0[0][X] == s0[2][X] - 2)
  # 1x2 rectangle:
  s1 = shapes[1]
  model.Add(s1[0][X] == s1[1][X])
  model.Add(s1[0][Y] == s1[1][Y] - 1)

  # No blocks can overlap:
  block_addresses = []
  for i, block in enumerate(blocks(shapes)):
    block_address = model.NewIntVar(0, (W+1)*(H+1), 'b%d' % (i,))
    model.Add(block[X] + (H+1)*block[Y] == block_address)
    block_addresses.append(block_address)
  model.AddAllDifferent(block_addresses)

  # Solve and print solutions as we find them
  solver = cp_model.CpSolver()
  solution_printer = SolutionPrinter(shapes)
  status = solver.SearchForAllSolutions(model, solution_printer)
  print('Status = %s' % solver.StatusName(status))
  print('Number of solutions found: %i' % solution_printer.count)


def blocks(shapes):
  ''' Helper to enumerate all blocks. '''
  for shape in shapes:
    for block in shape:
      yield block


class SolutionPrinter(cp_model.CpSolverSolutionCallback):
    ''' Print a solution. '''

    def __init__(self, variables):
        cp_model.CpSolverSolutionCallback.__init__(self)
        self.variables = variables
        self.count = 0

    def on_solution_callback(self):
      self.count += 1
      solution = [(self.Value(block[X]), self.Value(block[Y])) for shape in self.variables for block in shape]
      print((W+3)*'-')
      for y in range(0, H+1):
        print('|' + ''.join(['#' if (x,y) in solution else ' ' for x in range(0, W+1)]) + '|')
      print((W+3)*'-')


if __name__ == '__main__':
  main()

देता है:

...
------
|    |
| ###|
|  # |
|  # |
------
------
|    |
| ###|
|   #|
|   #|
------
Status = OPTIMAL
Number of solutions found: 60

नि: शुल्क नीति:

यदि हम कोशिकाओं के ग्रिड को एक ग्राफ मानते हैं, तो समस्या को फिर से समझा जा सकता है क्योंकि ग्रिड के कोशिकाओं के k- विभाजन को खोजने के लिए जहां प्रत्येक विभाजन का एक विशिष्ट आकार होता है और इसके अलावा प्रत्येक विभाजन एक जुड़ा घटक होता है । यानी AFAICT एक जुड़े घटक और एक पॉलोमिनो के बीच कोई अंतर नहीं है और इस उत्तर के बाकी हिस्से को यह धारणा बनाता है।

ओआर-टूल्स बाधा प्रोग्रामिंग में व्यक्त करने के लिए ग्रिड के कोशिकाओं के सभी संभावित "के-विभाजन जहां प्रत्येक विभाजन का एक विशिष्ट आकार होता है" बहुत तुच्छ है। लेकिन जुड़ा हुआ हिस्सा कठिन है AFAICT (मैंने कोशिश की और काफी समय तक असफल रहा ...)। मुझे लगता है कि OR-Tools बाधा प्रोग्रामिंग सही दृष्टिकोण नहीं है। मैंने देखा कि नेटवर्क ऑप्टिमाइज़ेशन लाइब्रेरी के लिए OR-C C ++ संदर्भ में जुड़े घटकों पर कुछ सामान है जो देखने लायक हो सकते हैं, लेकिन मैं इससे परिचित नहीं हूं। दूसरी ओर, पायथन में भोली पुनरावर्ती खोज समाधान काफी उल्लेखनीय है।

यहाँ एक "हाथ से" भोला समाधान है। यह बहुत धीमी है, लेकिन आपके 4x4 मामले के लिए सहने योग्य है। ग्रिड में प्रत्येक सेल की पहचान करने के लिए पते का उपयोग किया जाता है। ( इस एल्गोरिथ्म को एक भोले समाधान के रूप में कुछ करने के लिए विकी पृष्ठ के प्रकारों पर भी ध्यान दें और ऐसा लगता है कि यह समान पॉलीमिनो समस्याओं के लिए कुछ और कुशल सुझाव देता है)।

import numpy as np
from copy import copy
from tabulate import tabulate

D = 4 # Dimension of square grid.
KCC = [5,4,2,2] # List of the sizes of the required k connected components (KCCs).
assert(sum(KCC) <= D*D)
VALID_CELLS = range(2,D*D)

def search():
  solutions = set() # Stash of unique solutions.
  for start in VALID_CELLS: # Try starting search from each possible starting point and expand out.
    marked = np.zeros(D*D).tolist()
    _search(start, marked, set(), solutions, 0, 0)
  for solution in solutions:  # Print results.
    print(tabulate(np.array(solution).reshape(D, D)))
  print('Number of solutions found:', len(solutions))

def _search(i, marked, fringe, solutions, curr_count, curr_part):
  ''' Recursively find each possible KCC in the remaining available cells the find the next, until none left '''
  marked[i] = curr_part+1
  curr_count += 1
  if curr_count == KCC[curr_part]: # If marked K cells for the current CC move onto the next one.
    curr_part += 1
    if curr_part == len(KCC): # If marked K cells and there's no more CCs left we have a solution - not necessarily unique.
      solutions.add(tuple(marked))
    else:
      for start in VALID_CELLS:
        if marked[start] == 0:
          _search(start, copy(marked), set(), solutions, 0, curr_part)
  else:
    fringe.update(neighbours(i, D))
    while(len(fringe)):
      j = fringe.pop()
      if marked[j] == 0:
        _search(j, copy(marked), copy(fringe), solutions, curr_count, curr_part)

def neighbours(i, D):
  ''' Find the address of all cells neighbouring the i-th cell in a DxD grid. '''
  row = int(i/D)
  n = []
  n += [i-1] if int((i-1)/D) == row and (i-1) >= 0 else []
  n += [i+1] if int((i+1)/D) == row and (i+1) < D**2 else []
  n += [i-D] if (i-D) >=0 else []
  n += [i+D] if (i+D) < D**2 else []
  return filter(lambda x: x in VALID_CELLS, n)

if __name__ == '__main__':
  search()

देता है:

...
-  -  -  -
0  0  1  1
2  2  1  1
4  2  3  1
4  2  3  0
-  -  -  -
-  -  -  -
0  0  4  3
1  1  4  3
1  2  2  2
1  1  0  2
-  -  -  -
Number of solutions found: 3884

यह बहुत मददगार है, बहुत-बहुत धन्यवाद। एक बात जो समस्याग्रस्त है वह यह है कि आपका उदाहरण केवल निश्चित आकृतियों के पॉलीओमाइनो के लिए काम करता है, प्रश्न मुक्त पॉलीओमीनो (कोशिकाओं की निश्चित संख्या लेकिन विभिन्न आकारों के साथ, स्पष्टता के लिए प्रश्न संपादित किया जाएगा) के बारे में है। आपके उदाहरण के बाद, हमें S के प्रत्येक पॉलोमिनो के लिए हर संभव आकार (+ घुमाव + प्रतिबिंब) को हार्ड-कोड करना होगा ... जो व्यवहार्य नहीं है। प्रश्न बने हुए हैं, क्या OR- टूल्स के साथ ऐसी बाधाओं को लागू करना संभव है?
सोलह

ओह एक "मुक्त" हिस्सा याद किया। हम्म, अच्छी तरह से समस्या को रखा जा सकता है "25-ओमिनो के 5-विभाजन को ढूंढें जहां 25-ओमिनो को WxH ग्रिड के लिए विवश किया गया है, और प्रत्येक 5 विभाजन एक्स = (7,6,6,6) के लिए एक्स-ओमिनो भी है , 4,2) .. ”। मुझे लगता है कि यह OR-Tools में करना संभव है, लेकिन इसमें बदबू आ रही है, बस CSP पर नज़र रखने की गहराई को लागू करना आसान होगा, इसके लिए सीधे खोज करें: संभव 25-ominos। प्रत्येक संभव 25-ओमिनो के लिए, 25 डोमिनोज़ के भीतर एक एक्स-बिल्डिंग का चयन करके, जब तक कि आपको एक पूर्ण समाधान नहीं मिल जाता है या बैकट्रैक करना पड़ता है, तब एक एक्स-ओमिनो का चयन करके एक सीएसट्रैक खोज करते हैं।
स्पिंकस

भोली प्रत्यक्ष खोज आधारित समाधान की तरह कुछ जोड़ा जो मैंने पूर्ण टिप्पणी के लिए पिछली टिप्पणी में दिया था।
स्पिंकस

5

OR-Tools में बस कनेक्टेड क्षेत्र को कसने के लिए एक अपेक्षाकृत सीधा रास्ता अपनी सीमा को एक सर्किट बनाने के लिए विवश करना है । यदि आपके सभी पॉलीमिनोस का आकार 8 से कम है, तो हमें गैर-कनेक्टेड लोगों के बारे में चिंता करने की आवश्यकता नहीं है।

यह कोड सभी 3884 समाधान पाता है:

from ortools.sat.python import cp_model

cells = {(x, y) for x in range(4) for y in range(4) if x > 1 or y > 0}
sizes = [4, 2, 5, 2, 1]
num_polyominos = len(sizes)
model = cp_model.CpModel()

# Each cell is a member of one polyomino
member = {
    (cell, p): model.NewBoolVar(f"member{cell, p}")
    for cell in cells
    for p in range(num_polyominos)
}
for cell in cells:
    model.Add(sum(member[cell, p] for p in range(num_polyominos)) == 1)

# Each polyomino contains the given number of cells
for p, size in enumerate(sizes):
    model.Add(sum(member[cell, p] for cell in cells) == size)

# Find the border of each polyomino
vertices = {
    v: i
    for i, v in enumerate(
        {(x + i, y + j) for x, y in cells for i in [0, 1] for j in [0, 1]}
    )
}
edges = [
    edge
    for x, y in cells
    for edge in [
        ((x, y), (x + 1, y)),
        ((x + 1, y), (x + 1, y + 1)),
        ((x + 1, y + 1), (x, y + 1)),
        ((x, y + 1), (x, y)),
    ]
]
border = {
    (edge, p): model.NewBoolVar(f"border{edge, p}")
    for edge in edges
    for p in range(num_polyominos)
}
for (((x0, y0), (x1, y1)), p), border_var in border.items():
    left_cell = ((x0 + x1 + y0 - y1) // 2, (y0 + y1 - x0 + x1) // 2)
    right_cell = ((x0 + x1 - y0 + y1) // 2, (y0 + y1 + x0 - x1) // 2)
    left_var = member[left_cell, p]
    model.AddBoolOr([border_var.Not(), left_var])
    if (right_cell, p) in member:
        right_var = member[right_cell, p]
        model.AddBoolOr([border_var.Not(), right_var.Not()])
        model.AddBoolOr([border_var, left_var.Not(), right_var])
    else:
        model.AddBoolOr([border_var, left_var.Not()])

# Each border is a circuit
for p in range(num_polyominos):
    model.AddCircuit(
        [(vertices[v0], vertices[v1], border[(v0, v1), p]) for v0, v1 in edges]
        + [(i, i, model.NewBoolVar(f"vertex_loop{v, p}")) for v, i in vertices.items()]
    )

# Print all solutions
x_range = range(min(x for x, y in cells), max(x for x, y in cells) + 1)
y_range = range(min(y for x, y in cells), max(y for x, y in cells) + 1)
solutions = 0


class SolutionPrinter(cp_model.CpSolverSolutionCallback):
    def OnSolutionCallback(self):
        global solutions
        solutions += 1
        for y in y_range:
            print(
                *(
                    next(
                        p
                        for p in range(num_polyominos)
                        if self.Value(member[(x, y), p])
                    )
                    if (x, y) in cells
                    else "-"
                    for x in x_range
                )
            )
        print()


solver = cp_model.CpSolver()
solver.SearchForAllSolutions(model, SolutionPrinter())
print("Number of solutions found:", solutions)

4

प्रत्येक पॉलीमोनिनो, और प्रत्येक संभावित शीर्ष बाएं सेल के लिए, आपके पास एक बूलियन चर है जो इंगित करता है कि यह सेल एन्कोडिंग आयत का शीर्ष बाएं भाग है।

प्रत्येक सेल और प्रत्येक पॉलोमिनो के लिए, आपके पास एक बूलियन चर है जो इंगित करता है कि क्या यह सेल इस पॉलीमिनो द्वारा कब्जा कर लिया गया है।

अब, प्रत्येक सेल और प्रत्येक पॉलोमिनो के लिए, आपके पास निहितार्थों की एक श्रृंखला है: शीर्ष बाएं सेल का अर्थ है कि प्रत्येक सेल वास्तव में इस पॉलोमिनो के कब्जे में है।

फिर बाधाएं: प्रत्येक कोशिका के लिए, प्रत्येक पॉलीओमिनो के लिए अधिकांश पॉलीमिनो उस पर कब्जा कर लेता है, ठीक एक सेल है जो इसका शीर्ष बाएं भाग है।

यह एक शुद्ध बूलियन समस्या है।


आपके उत्तर के लिए बहुत धन्यवाद ! मुझे ईमानदारी से पता नहीं है कि इसे या टूल्स के साथ कैसे लागू किया जाए, क्या कोई उदाहरण है (उपलब्ध अजगर उदाहरणों से) जो आप मुझे शुरू करने में मदद करने के लिए विशेष रूप से सुझाव देंगे?
solub

मुझे वास्तव में खेद है क्योंकि मैं वास्तव में आपके उत्तर को नहीं समझ रहा हूँ। निश्चित नहीं है कि "एनक्लोजिंग रेक्टेंगल" किसका उल्लेख कर रहा है या "प्रत्येक सेल और प्रत्येक पॉलीओमिनो के लिए" कोड में कैसे अनुवाद किया जाएगा ('नेस्ट' लूप?)। किसी भी तरह, क्या आप मुझे बताएंगे कि क्या आपका स्पष्टीकरण नि: शुल्क पॉलीओमीनो के मामले को संबोधित करता है (प्रश्न को स्पष्टता के लिए संपादित किया गया है)।
सोलूब
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.