স্যাট-সলভার (পাইথন) দিয়ে একটি নির্দিষ্ট অঞ্চলে ফ্রি পলিমিনোজগুলির সমস্ত সংমিশ্রণগুলি সন্ধান করা হচ্ছে


15

আমি স্যাট সমাধানকারীদের বিশ্বে নতুন এবং নিম্নলিখিত সমস্যা সম্পর্কিত কিছু গাইডেন্সের প্রয়োজন।

এটি বিবেচনা করে:

❶ আমার কাছে একটি 4 * 4 গ্রিডে 14 সংলগ্ন ঘরগুলির একটি নির্বাচন রয়েছে

❷ আমার কাছে 4, 2, 5, 2 এবং 1 টি আকারের 5 টি পলিওমিনোস (এ, বি, সি, ডি, ই) রয়েছে

Poly এই পলিওমিনোগুলি নিখরচায় , অর্থাত তাদের আকৃতি স্থির নয় এবং বিভিন্ন নিদর্শন তৈরি করতে পারে

এখানে চিত্র বর্ণনা লিখুন

আমি কীভাবে স্যাট-সলভারের সাথে নির্বাচিত অঞ্চলের (ধূসর রঙের কোষ) অভ্যন্তরে এই 5 টি ফ্রি পলিওমিনোজগুলির সমস্ত সম্ভাব্য সংমিশ্রণগুলি গণনা করতে পারি ?

@ স্পিংকাসের অন্তর্দৃষ্টিপূর্ণ উত্তর এবং ওআর-সরঞ্জামের ডকুমেন্টেশন উভয় থেকে ধার নেওয়া আমি নিম্নলিখিত উদাহরণ কোডটি তৈরি করতে পারি (একটি বৃহত্তর নোটবুকে রান):

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)

এখানে চিত্র বর্ণনা লিখুন

সমস্যাটি হ'ল আমার কাছে হার্ড-কোডড ৫ টি অনন্য / ফিক্সড পলিওমিনোস রয়েছে এবং প্রতিবন্ধকতাগুলি কীভাবে সংজ্ঞায়িত করতে হয় তা আমি জানি না যাতে প্রতিটি পলিওমিনোগুলির জন্য প্রতিটি সম্ভাব্য প্যাটার্ন বিবেচনায় নেওয়া হয় (তবে এটি সম্ভব হয়)।


আমি প্রথমবার গুগল ওআর-সরঞ্জাম সম্পর্কে শুনি। এটা যেমন মান পাইথন লাইব্রেরী ব্যবহার করা সম্ভব itertools, numpy, networkx?
ম্যাথফাক্স

আমি একটি স্যাট-সলভার বা সরঞ্জামগুলি বেশি পছন্দ করতে পছন্দ করি।
একসাথে

@ সলুব, মিনিজিংক ভাষা ব্যবহার করে এই জাতীয় সমস্যাটিকে মডেল করা / সমাধান করা বেশ সহজ, যেহেতু কোনও পৃষ্ঠে অনিয়মিত বস্তু স্থাপনের জন্য উচ্চ-স্তরের প্রতিবন্ধকতা রয়েছে। আপনি যদি কুরসেরাতে "অ্যাডভান্সড মডেলিং ফর ডিস্রিট অপটিমাইজেশন" ফ্রি কোর্সটি অতিক্রম করেন তবে আপনাকে কীভাবে এটি করতে হবে তা শেখানো হবে এবং এর কয়েকটি বাস্তব (এবং আরও জটিল) উদাহরণ দেওয়া হবে। অ্যান্ড-টুলসটির মিনিজিংক ভাষার জন্য একটি ইন্টারফেস রয়েছে, তাই আপনি দ্রুত সমাধান খুঁজে পাওয়ার জন্য এর শক্তিকে আরও বাড়িয়ে তুলতে পারেন।
প্যাট্রিক ট্রেনটিন

1
আকর্ষণীয় বলে মনে হচ্ছে, পয়েন্টারের জন্য ধন্যবাদ। নিশ্চিত না যে এটি আমার যে নির্দিষ্ট সমস্যার সাথে জবাব দেবে (ফ্রি পলিওমিনোস জড়িত সংজ্ঞাগুলি স্থির নয়) তবে আমি অবশ্যই এটি লক্ষ্য করব।
solub

1
আমাকে অবশ্যই ক্ষমা চাইতে হবে, আমি এই প্রশ্নটি সম্পর্কে পুরোপুরি ভুলে গিয়েছিলাম। একটি হয়েছে সংশ্লিষ্ট প্রশ্ন মধ্যে minizincএকটি বিস্তারিত উত্তর যে ব্যবহার সম্পর্কে আমার আগের পরামর্শ জুড়ে দিয়ে ট্যাগ minizinc
প্যাট্রিক ট্রেনটিন

উত্তর:


10

সম্পাদনা: আমি মূল উত্তরে "ফ্রি" শব্দটি মিস করেছি এবং স্থির পলিওমিনোসগুলির জন্য ওআর-সরঞ্জাম ব্যবহার করে উত্তর দিয়েছি। ফ্রি পলিওমিনোসের সমাধান অন্তর্ভুক্ত করার জন্য উত্তরের জন্য একটি বিভাগ যুক্ত করা হয়েছে - এএএএফআইসিটি ওআর-সরঞ্জামগুলির সাথে সীমাবদ্ধ প্রোগ্রামিংয়ে স্পষ্টভাবে প্রকাশ করা বেশ কঠিন বলে প্রমাণিত হয়।

বা সরঞ্জামের সাথে ফিক্সড পোলিয়ামিনোগুলি:

হ্যাঁ আপনি ওআর-সরঞ্জামগুলিতে সীমাবদ্ধ প্রোগ্রামিংয়ের মাধ্যমে এটি করতে পারেন । ওআর-সরঞ্জামগুলি 2 ডি গ্রিড জ্যামিতি সম্পর্কে কিছুই জানে না তাই আপনার অবস্থানগত সীমাবদ্ধতার ক্ষেত্রে আপনার প্রতিটি আকারের জ্যামিতি এনকোড করতে হবে। অর্থাত্ একটি আকৃতি ব্লক / কোষের সংকলন যা একে অপরের সাথে একটি নির্দিষ্ট সম্পর্ক থাকতে হবে, অবশ্যই গ্রিডের সীমানার মধ্যে থাকতে হবে এবং অবশ্যই ওভারল্যাপ হওয়া উচিত নয়। আপনার নিজের সীমাবদ্ধতা মডেলটি একবার হয়ে গেলে আপনি সিপি-স্যাট সলভারকে এটির সমাধান করতে বলবেন , আপনার ক্ষেত্রে, সমস্ত সম্ভাব্য সমাধানের জন্য।

এখানে একটি 4x4 গ্রিডে দুটি আয়তক্ষেত্র আকৃতির ধারণার একটি সত্য প্রমাণ যেহেতু হাত দিয়ে সীমাবদ্ধতাগুলি ইনপুট করা কিছুটা ক্লান্তিকর)।

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-পার্টিশন খোঁজার সংযুক্ত উপাদান । অর্থাত্ সংযুক্ত উপাদান এবং পলিওমিনোর মধ্যে কোনও পার্থক্য নেই এবং এই উত্তরটির বাকী অংশটি অনুমান করে তোলে।

OR- সরঞ্জাম সীমাবদ্ধতা প্রোগ্রামিংয়ে প্রকাশ করার জন্য গ্রিডের সমস্ত কক্ষের কে-পার্টিশনগুলি যেখানে প্রতিটি পার্টিশনের একটি নির্দিষ্ট আকার রয়েছে সেখানে সন্ধান করা অত্যন্ত তুচ্ছ। তবে সংযোগের অংশটি শক্ত এএএএফসিটি (আমি চেষ্টা করেছিলাম এবং বেশ কিছুক্ষণ ব্যর্থ হয়েছি ...)। আমি মনে করি ওআর-টুলস সীমাবদ্ধ প্রোগ্রামিং সঠিক পদ্ধতির নয়। আমি লক্ষ্য করেছি যে নেটওয়ার্ক অপ্টিমাইজেশন লাইব্রেরিগুলির জন্য OR- সরঞ্জাম সি ++ রেফারেন্সের সাথে সংযুক্ত উপাদানগুলিতে কিছু স্টাফ রয়েছে যা দেখতে পারাও উপযুক্ত তবে আমি এর সাথে পরিচিত নই। অন্যদিকে পাইথনে নিষ্পাপ পুনরাবৃত্ত অনুসন্ধানের সমাধান বেশ কার্যকর is

এখানে একটি "হাত দ্বারা" নিষ্পাপ সমাধান রয়েছে। এটি বেশ ধীর কিন্তু আপনার 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

এটি খুব সহায়ক, আপনাকে অনেক ধন্যবাদ। সমস্যাযুক্ত একটি জিনিস হ'ল আপনার উদাহরণটি কেবল স্থির আকারের পলিওমিনোসগুলির জন্য কাজ করে, প্রশ্নটি ফ্রি পলিমিনয়েস সম্পর্কে (কোষের নির্দিষ্ট সংখ্যার সাথে তবে বিভিন্ন আকারের সাথে, প্রশ্নটি স্পষ্টতার জন্য সম্পাদনা করা হবে)। আপনার উদাহরণ অনুসরণ করে, আমাদের আকারের প্রতিটি পলিওমিনোর জন্য প্রতিটি সম্ভাব্য আকার (+ রোটেশন + প্রতিবিম্ব) হার্ড-কোড করতে হবে ... যা কার্যকর নয়। প্রশ্নগুলি রয়ে গেছে, ওআর-সরঞ্জামগুলির সাহায্যে কি এই জাতীয় বাধা কার্যকর করা সম্ভব?
solub

ওহ, "ফ্রি" অংশটি মিস করেছেন। হুঁ, সমস্যাটি "25-ওমিনোর 5-পার্টিশন সন্ধান করতে পারেন যেখানে 25-ওমিনো একটি ডাব্লুএক্সএইচ গ্রিডে সীমাবদ্ধ, এবং প্রতিটি 5 টি পার্টিশন এক্স = এর জন্য এক্স-ওমিনো (7,6,6) , 4,2) .. "। আমি অনুমান করি যে এটি ওআর-সরঞ্জামগুলিতে করা সম্ভব তবে এটির গন্ধে মনে হচ্ছে কেবল সিএসপি ব্যাক ট্র্যাকিংয়ের গভীরতা প্রথমে এটির জন্য সরাসরি অনুসন্ধান কার্যকর করা সহজ হবে: সম্ভব 25-ওমোনোস সন্ধান করুন। প্রতিটি সম্ভাব্য 25-ওমিনোর জন্য 25 ডোমিনোর মধ্যে একটি এক্স-ওমিনো নির্মাণের জন্য একটি এক্স পছন্দ করে একটি ব্যাকট্র্যাকিং সিএসপি অনুসন্ধান করুন, যতক্ষণ না আপনি একটি সম্পূর্ণ সমাধান খুঁজে পান বা ব্যাকট্র্যাক না করে।
স্পিঙ্কাস

পরিপূর্ণতার জন্য পূর্ববর্তী মন্তব্যে আমি নির্দোষ সরাসরি অনুসন্ধান ভিত্তিক সমাধানের মতো কিছু যুক্ত করেছি।
স্পিঙ্কাস

5

ওআর-সরঞ্জামগুলিতে সহজভাবে সংযুক্ত অঞ্চলকে সীমাবদ্ধ করার একটি অপেক্ষাকৃত সরলতম উপায় হ'ল এর সীমানাটি একটি সার্কিট হিসাবে সীমাবদ্ধ করা । যদি আপনার সমস্ত পলিমিনোগুলি 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

আমি আপনার উত্তরটি সত্যই বুঝতে পারছি না বলে আমি সত্যই দুঃখিত। নিশ্চিত নয় যে "enclosing আয়তক্ষেত্র" কোনটি উল্লেখ করছে বা কীভাবে "প্রতিটি কক্ষ এবং প্রতিটি পলিওমিনো" কোডে অনুবাদ করা হবে ('লুপের জন্য নেস্টেড'?)। যাইহোক, আপনার ব্যাখ্যাটি ফ্রি পলিওমিনোসের ক্ষেত্রে প্রশ্নটি সুস্পষ্টভাবে প্রকাশ করেছে কিনা (প্রশ্নটি স্পষ্টতার জন্য সম্পাদনা করা হয়েছে) আপনি কি বলতে চাইবেন না?
solub
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.