পৌঁছনীয় সাপের অভিযানের সংখ্যা


11

এই চ্যালেঞ্জটি খেলা সাপ সম্পর্কে নয়।

দৈর্ঘ্যের একটি অনুভূমিক রেখা অঙ্কন করে গঠিত 2 ডি সাপটি কল্পনা করুন n। তার দেহ বরাবর পূর্ণসংখ্যার পয়েন্টগুলিতে, এই সাপটি তার দেহটি 90 ডিগ্রি ঘোরান। যদি আমরা সাপটির সামনের দিকটি শুরু করতে খুব বাম দিকে থাকতে সংজ্ঞায়িত করি তবে ঘূর্ণনটি সাপের পিছনের অংশটি সরিয়ে ফেলবে এবং সামনের অংশটি রাখা থাকবে। বারবার ঘোরানোর মাধ্যমে এটি প্রচুর সাপের দেহের আকার তৈরি করতে পারে।

বিধি

  1. সাপের দেহের একটি অংশ অন্য অংশকে ওভারল্যাপ করতে পারে না।
  2. সাপের দেহের কোনও অংশের মধ্যে ওভারল্যাপিং না করে চূড়ান্ত অভিযোজনে পৌঁছানো সম্ভব হবে। দুটি সমস্যা যা স্পর্শ করে এই সমস্যাটিতে ওভারল্যাপিং হিসাবে গণনা করা হয়।
  3. আমি একটি সাপ এবং এর বিপরীতকে একই আকৃতি হিসাবে বিবেচনা করি।

কার্য

আবর্তন, অনুবাদ এবং আয়না প্রতিসাম্য পর্যন্ত, বিভিন্ন সাপের শরীরের আকারের মোট সংখ্যা কতটি হতে পারে?

সাপের দেহের অংশের আবর্তনের উদাহরণ। কল্পনা করুন n=10এবং সাপটি একটি সরলরেখার সূচনামুখর দিকে রয়েছে। 4ঘড়ির কাঁটার বিপরীতে 90 ডিগ্রি পয়েন্টে ঘোরান । আমরা থেকে সাপ পেতে 4থেকে 10থেকে (সাপের লেজ) উল্লম্বভাবে মিথ্যা এবং সর্প 0থেকে 4অনুভূমিকভাবে মিথ্যা। সাপের শরীরে এখন একটি ডান কোণ রয়েছে।

এখানে কিছু উদাহরণ মার্টিন বাটনারকে ধন্যবাদ।

আমরা অনুভূমিক সাপ দিয়ে শুরু করি।

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

এখন আমরা অবস্থান 4 থেকে ঘোরান।

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

আমরা এই দিকনির্দেশে ঘোরার পরে শেষ করি।

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

এখন আসুন আমরা একটি ভিন্ন সাপের এই দৃষ্টিভঙ্গি বিবেচনা করি।

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

আমরা এখন একটি অবৈধ পদক্ষেপ দেখতে পাই যেখানে ঘূর্ণনের সময় একটি ওভারল্যাপ হবে।

সংঘর্ষের উদাহরণ

স্কোর

আপনার স্কোর সবচেয়ে বড় nযার জন্য আপনার কোডটি আমার কম্পিউটারে এক মিনিটেরও কম সময়ে সমস্যার সমাধান করতে পারে।

যখন কোনও ঘূর্ণন ঘটে তখন এটি তার সাথে সাপের অর্ধেক সরানো হবে। আমাদের এই চিন্তার দরকার নেই যে এই অংশটি ঘোরানো হয় যে কোনওটি ঘোরার সময় সাপের একটি অংশকে ওভারল্যাপ করতে পারে। সরলতার জন্য আমরা ধরে নিতে পারি সাপের প্রস্থ শূন্য রয়েছে। আপনি কেবল সাপের কোনও নির্দিষ্ট পয়েন্টে ঘড়ির কাঁটার বিপরীতে 90 ডিগ্রি পর্যন্ত ঘুরতে পারেন। কারণ, আপনি কখনই এই সাপটিকে দুটি ভাগে ভাঁজ করতে পারবেন না কারণ একই দিকে একই পয়েন্টে দুটি ঘূর্ণন জড়িত ছিল।

যে আকার তৈরি করা যায় না

যে আকার তৈরি করা যায় না তার একটি সাধারণ উদাহরণ হ'ল মূলধন T। আরও পরিশীলিত সংস্করণটি হ'ল

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

(এই উদাহরণের জন্য হ্যারাল্ড হানচে-ওলসেনকে ধন্যবাদ)

এই উদাহরণে উল্লিখিতগুলির সাথে সংলগ্ন সমস্ত অনুভূমিক রেখা 1 টি পৃথক রয়েছে। সুতরাং এই অবস্থান থেকে কোনও আইনী পদক্ষেপ নেই এবং সমস্যাটি যেমন বিপরীতমুখী তাই আরম্ভের অবস্থান থেকে সেখানে যাওয়ার কোনও উপায় নেই।

ভাষা ও গ্রন্থাগার

আপনি যে কোনও ভাষা নিখরচায় উপলব্ধ সংকলক / দোভাষী / ইত্যাদি ব্যবহার করতে পারেন। লিনাক্স এবং যে কোনও লাইব্রেরির জন্য লিনাক্সের জন্য নিখরচায় উপলব্ধ।

আমার মেশিনের সময়গুলি আমার মেশিনে চালিত হবে। এটি একটি এএমডি এফএক্স-8350 এইট-কোর প্রসেসরে স্ট্যান্ডার্ড উবুন্টু ইনস্টল। এর অর্থ হল আপনার কোডটি চালাতে আমার সক্ষম হওয়া দরকার। ফলস্বরূপ, কেবল সহজেই উপলভ্য নিখরচায় সফ্টওয়্যার ব্যবহার করুন এবং দয়া করে আপনার কোডটি কীভাবে সংকলন করতে এবং চালাতে হয় তার সম্পূর্ণ নির্দেশাবলী অন্তর্ভুক্ত করুন।


1
@ টিপিসেলা প্রশ্নগুলির জন্য ধন্যবাদ। যখন আমি বলি "যখন কোনও ঘূর্ণন ঘটে তখন এটি দিয়ে একটি অর্ধেক সাপ সরে যাবে" আমি 50 শতাংশ বোঝাতে চাইনি। আমি কেবল ঘূর্ণন বিন্দুর আগে অংশটি এবং তার পরে অংশটি উল্লেখ করছি। আপনি যদি সাপ ধরে 0 থেকে আবর্তিত হন তবে আপনি পুরো জিনিসটি ঘোরান!

2
আপনার দ্বিতীয় প্রশ্ন সম্পর্কে @ টিপিসেলা মুল বক্তব্যটি হ'ল আমি যে অবস্থান দিয়েছি তা থেকে কোনও আইনী আবর্তন নেই। যদি এটি পৌঁছনীয় হয় তবে অবশ্যই আবর্তনগুলির ক্রম দ্বারা অনুভূমিক প্রারম্ভিক দিকটি ফিরে পাওয়া সম্ভব হবে (শেষের দিকে যাওয়ার জন্য আপনি যা করেছেন তার বিপরীতে)) আপনি যে আইনী ঘূর্ণনটি করতে পারেন বলে আপনি কী বর্ণনা করতে পারবেন? এই অবস্থান থেকে? পরিষ্কার করে বলতে গেলে সাপ বড় হয় না। এটি সর্বদা সর্বদা একই দৈর্ঘ্য থাকে।

3
@ ট্যাপিসেলা মনে হচ্ছে আপনি সাপটি বাড়ার প্রত্যাশা করছেন। যদিও এর আকার ঠিক করা হয়েছে। আপনি একটি দীর্ঘ সাপ দিয়ে শুরু করেন এবং আপনাকে যা করতে দেওয়া হ'ল এটির 90 ডিগ্রি দ্বারা কিছু অংশ ভাজতে হবে। বর্তমান অবস্থান থেকে আপনি এমন কোনও ভাঁজ প্রয়োগ করতে পারবেন না যা সাপের আগের পর্যায়ে নিয়ে যাবে।
মার্টিন ইন্ডার

1
আপনি কি এক পর্যায়ে একাধিক বার ভাঁজ করতে পারেন (পিছনে এবং পিছনে)? যদি আপনি এটি করতে পারেন এটি জটিল।
এলোমেলো

1
@ আরন্দোমরা আপনি যতক্ষণ না সরাসরি fromন ডিগ্রি থেকে আরও বেশি কিছু না এগিয়ে যেতে পারেন।

উত্তর:


5

পাইথন 3 - অস্থায়ী স্কোর: এন = 11 (পিপিওয়াই * সহ এন = 13)

যেহেতু প্রথম সপ্তাহে কোনও উত্তর নেই, তাই প্রতিযোগিতাটি উত্সাহিত করার জন্য পাইথনের একটি উদাহরণ এখানে। আমি এটিকে যুক্তিযুক্তভাবে পঠনযোগ্য করে তোলার চেষ্টা করেছি যাতে অন্য উত্তরগুলির জন্য ধারণা দেওয়ার জন্য অদক্ষতাগুলি সহজেই চিহ্নিত করা যায়।

অভিগমন

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

কোড

(এখন আমার ভুল প্রথম প্রয়াসের পরে কিছু দস্তাবেজ এবং জোর দিয়ে)

'''
Snake combinations

A snake is represented by a tuple giving the relative orientation at each joint.
A length n snake has n-1 joints.
Each relative orientation is one of the following:

0: Clockwise 90 degrees
1: Straight
2: Anticlockwise 90 degrees

So a straight snake of length 4 has 3 joints all set to 1:

(1, 1, 1)

x increases to the right
y increases upwards

'''


import turtle


def all_coords(state):
    '''Return list of coords starting from (0,0) heading right.'''
    current = (1, 0)
    heading = 0
    coords = [(0,0), (1,0)]
    for item in state:
        heading += item + 3
        heading %= 4
        offset = ((1,0), (0,1), (-1,0), (0,-1))[heading]
        current = tuple(current[i]+offset[i] for i in (0,1))
        coords.append(current)
    return coords


def line_segments(coords, pivot):
    '''Return list of line segments joining consecutive coords up to pivot-1.'''
    return [(coords[i], coords[i+1]) for i in range(pivot+1)]


def rotation_direction(coords, pivot, coords_in_final_after_pivot):
    '''Return -1 if turning clockwise, 1 if turning anticlockwise.'''
    pivot_coord = coords[pivot + 1]
    initial_coord = coords[pivot + 2]
    final_coord = coords_in_final_after_pivot[0]
    initial_direction = tuple(initial_coord[i] - pivot_coord[i] for i in (0,1))
    final_direction = tuple(final_coord[i] - pivot_coord[i] for i in (0,1))
    return (initial_direction[0] * final_direction[1] -
            initial_direction[1] * final_direction[0]
            )


def intersects(arc, line):
    '''Return True if the arc intersects the line segment.'''
    if line_segment_cuts_circle(arc, line):
        cut_points = points_cutting_circle(arc, line)
        if cut_points and cut_point_is_on_arc(arc, cut_points):
            return True


def line_segment_cuts_circle(arc, line):
    '''Return True if the line endpoints are not both inside or outside.'''
    centre, point, direction = arc
    start, finish = line
    point_distance_squared = distance_squared(centre, point)
    start_distance_squared = distance_squared(centre, start)
    finish_distance_squared = distance_squared(centre, finish)
    start_sign = start_distance_squared - point_distance_squared
    finish_sign = finish_distance_squared - point_distance_squared
    if start_sign * finish_sign <= 0:
        return True


def distance_squared(centre, point):
    '''Return the square of the distance between centre and point.'''
    return sum((point[i] - centre[i]) ** 2 for i in (0,1))


def cut_point_is_on_arc(arc, cut_points):
    '''Return True if any intersection point with circle is on arc.'''
    centre, arc_start, direction = arc
    relative_start = tuple(arc_start[i] - centre[i] for i in (0,1))
    relative_midpoint = ((relative_start[0] - direction*relative_start[1])/2,
                         (relative_start[1] + direction*relative_start[0])/2
                         )
    span_squared = distance_squared(relative_start, relative_midpoint)
    for cut_point in cut_points:
        relative_cut_point = tuple(cut_point[i] - centre[i] for i in (0,1))
        spacing_squared = distance_squared(relative_cut_point,
                                           relative_midpoint
                                           )
        if spacing_squared <= span_squared:
            return True


def points_cutting_circle(arc, line):
    '''Return list of points where line segment cuts circle.'''
    points = []
    start, finish = line
    centre, arc_start, direction = arc
    radius_squared = distance_squared(centre, arc_start)
    length_squared = distance_squared(start, finish)
    relative_start = tuple(start[i] - centre[i] for i in (0,1))
    relative_finish = tuple(finish[i] - centre[i] for i in (0,1))
    relative_midpoint = tuple((relative_start[i] +
                               relative_finish[i]
                               )*0.5 for i in (0,1))
    determinant = (relative_start[0]*relative_finish[1] -
                   relative_finish[0]*relative_start[1]
                   )
    determinant_squared = determinant ** 2
    discriminant = radius_squared * length_squared - determinant_squared
    offset = tuple(finish[i] - start[i] for i in (0,1))
    sgn = (1, -1)[offset[1] < 0]
    root_discriminant = discriminant ** 0.5
    one_over_length_squared = 1 / length_squared
    for sign in (-1, 1):
        x = (determinant * offset[1] +
             sign * sgn * offset[0] * root_discriminant
             ) * one_over_length_squared
        y = (-determinant * offset[0] +
             sign * abs(offset[1]) * root_discriminant
             ) * one_over_length_squared
        check = distance_squared(relative_midpoint, (x,y))
        if check <= length_squared * 0.25:
            points.append((centre[0] + x, centre[1] + y))
    return points


def potential_neighbours(candidate):
    '''Return list of states one turn away from candidate.'''
    states = []
    for i in range(len(candidate)):
        for orientation in range(3):
            if abs(candidate[i] - orientation) == 1:
                state = list(candidate)
                state[i] = orientation
                states.append(tuple(state))
    return states


def reachable(initial, final):
    '''
    Return True if final state can be reached in one legal move.

    >>> reachable((1,0,0), (0,0,0))
    False

    >>> reachable((0,1,0), (0,0,0))
    False

    >>> reachable((0,0,1), (0,0,0))
    False

    >>> reachable((1,2,2), (2,2,2))
    False

    >>> reachable((2,1,2), (2,2,2))
    False

    >>> reachable((2,2,1), (2,2,2))
    False

    >>> reachable((1,2,1,2,1,1,2,2,1), (1,2,1,2,1,1,2,1,1))
    False

    '''
    pivot = -1
    for i in range(len(initial)):
        if initial[i] != final[i]:
            pivot = i
            break

    assert pivot > -1, '''
        No pivot between {} and {}'''.format(initial, final)
    assert initial[pivot + 1:] == final[pivot + 1:], '''
        More than one pivot between {} and {}'''.format(initial, final)

    coords_in_initial = all_coords(initial)
    coords_in_final_after_pivot = all_coords(final)[pivot+2:]
    coords_in_initial_after_pivot = coords_in_initial[pivot+2:]
    line_segments_up_to_pivot = line_segments(coords_in_initial, pivot)

    direction = rotation_direction(coords_in_initial,
                                   pivot,
                                   coords_in_final_after_pivot
                                   )

    pivot_point = coords_in_initial[pivot + 1]

    for point in coords_in_initial_after_pivot:
        arc = (pivot_point, point, direction)
        if any(intersects(arc, line) for line in line_segments_up_to_pivot):
            return False
    return True


def display(snake):
    '''Display a line diagram of the snake.

    Accepts a snake as either a tuple:

    (1, 1, 2, 0)

    or a string:

    "1120"

    '''
    snake = tuple(int(s) for s in snake)
    coords = all_coords(snake)

    turtle.clearscreen()
    t = turtle.Turtle()
    t.hideturtle()
    s = t.screen
    s.tracer(0)

    width, height = s.window_width(), s.window_height()

    x_min = min(coord[0] for coord in coords)
    x_max = max(coord[0] for coord in coords)
    y_min = min(coord[1] for coord in coords)
    y_max = max(coord[1] for coord in coords)
    unit_length = min(width // (x_max - x_min + 1),
                      height // (y_max - y_min + 1)
                      )

    origin_x = -(x_min + x_max) * unit_length // 2
    origin_y = -(y_min + y_max) * unit_length // 2

    pen_width = max(1, unit_length // 20)
    t.pensize(pen_width)
    dot_size = max(4, pen_width * 3)

    t.penup()
    t.setpos(origin_x, origin_y)
    t.pendown()

    t.forward(unit_length)
    for joint in snake:
        t.dot(dot_size)
        t.left((joint - 1) * 90)
        t.forward(unit_length)
    s.update()


def neighbours(origin, excluded=()):
    '''Return list of states reachable in one step.'''
    states = []
    for candidate in potential_neighbours(origin):
        if candidate not in excluded and reachable(origin, candidate):
            states.append(candidate)
    return states


def mirrored_or_backwards(candidates):
    '''Return set of states that are equivalent to a state in candidates.'''
    states = set()
    for candidate in candidates:
        mirrored = tuple(2 - joint for joint in candidate)
        backwards = candidate[::-1]
        mirrored_backwards = mirrored[::-1]
        states |= set((mirrored, backwards, mirrored_backwards))
    return states


def possible_snakes(snake):
    '''
    Return the set of possible arrangements of the given snake.

    >>> possible_snakes((1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1))
    {(1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1)}

    '''
    reached = set()
    candidates = set((snake,))

    while candidates:
        candidate = candidates.pop()
        reached.add(candidate)
        new_candidates = neighbours(candidate, reached)
        reached |= mirrored_or_backwards(new_candidates)
        set_of_new_candidates = set(new_candidates)
        reached |= set_of_new_candidates
        candidates |= set_of_new_candidates

    excluded = set()
    final_answers = set()
    while reached:
        candidate = reached.pop()
        if candidate not in excluded:
            final_answers.add(candidate)
            excluded |= mirrored_or_backwards([candidate])

    return final_answers


def straight_derived_snakes(length):
    '''Return the set of possible arrangements of a snake of this length.'''
    straight_line = (1,) * max(length-1, 0)
    return possible_snakes(straight_line)


if __name__ == '__main__':
    import doctest
    doctest.testmod()
    import sys
    arguments = sys.argv[1:]
    if arguments:
        length = int(arguments[0])
    else:
        length = int(input('Enter the length of the snake:'))
    print(len(straight_derived_snakes(length)))

ফলাফল

আমার মেশিনে দীর্ঘতম সাপটি 1 মিনিটের নিচে গণনা করা যায় দৈর্ঘ্য 11 (বা পিপাই * দিয়ে দৈর্ঘ্য 13)। লেম্বিকের মেশিন থেকে অফিশিয়াল স্কোর কী তা আমরা খুঁজে না পাওয়া পর্যন্ত এটি স্পষ্টতই একটি অস্থায়ী স্কোর।

তুলনার জন্য, এখানে এন এর প্রথম কয়েকটি মানগুলির ফলাফল:

 n | reachable orientations
-----------------------------
 0 | 1
 1 | 1
 2 | 2
 3 | 4
 4 | 9
 5 | 22
 6 | 56
 7 | 147
 8 | 388
 9 | 1047
10 | 2806
11 | 7600
12 | 20437
13 | 55313
14 | 148752
15 | 401629
16 | 1078746
17 | MemoryError (on my machine)

এর মধ্যে যদি কোনওটি ভুল হয়ে যায় তবে দয়া করে আমাকে জানান let

যদি আপনার কাছে এমন কোনও ব্যবস্থার উদাহরণ রয়েছে যা উন্মুক্ত করা সম্ভব হবে না, আপনি neighbours(snake)কোডটির পরীক্ষা হিসাবে এক ধাপে পৌঁছাতে সক্ষম কোনও ব্যবস্থা খুঁজে পেতে ফাংশনটি ব্যবহার করতে পারেন । snakeযৌথ দিকনির্দেশের একটি দ্বিগুণ (ঘড়ির কাঁটার জন্য 0, সরাসরি জন্য 1, অ্যান্টিক্লোকের জন্য 2)। উদাহরণস্বরূপ (1,1,1) হ'ল দৈর্ঘ্যের একটি সরল সাপ 4 (3 টি জোড় সহ)।

কল্পনা

আপনার মনে যে কোনও সাপ বা যে কোনও সাপ ফিরে পেয়েছিল তা কল্পনা neighboursকরতে আপনি ফাংশনটি ব্যবহার করতে পারেন display(snake)। এটি অন্যান্য ফাংশনের মতো একটি টুপল গ্রহণ করে, তবে এটি যেহেতু মূল প্রোগ্রামটি ব্যবহার করে না এবং তাই দ্রুত হওয়ার দরকার নেই, এটি আপনার সুবিধার্থে একটি স্ট্রিংও গ্রহণ করবে।

display((1,1,2,0)) সমতুল্য display("1120")

লেম্বিক মন্তব্যে যেমন উল্লেখ করেছেন, আমার ফলাফলগুলি OEIS A037245 এর সাথে সমান, যা ঘোরানোর সময় ছেদগুলিকে বিবেচনা করে না। এটি কারণ n এর প্রথম কয়েকটি মানের জন্য কোনও পার্থক্য নেই - সমস্ত আকার যা স্ব-ছেদ না করে একটি সরল সাপ ভাঁজ করে পৌঁছতে পারে। কোডটির নির্ভুলতা neighbours()এমন একটি সাপকে কল করে পরীক্ষা করা যেতে পারে যা ছেদ ছাড়াই প্রকাশ করা যায় না। যেহেতু এর কোনও প্রতিবেশী নেই, এটি কেবল OEIS ক্রমকে অবদান রাখবে, এবং এটির জন্য নয়। আমি যে ছোট্ট উদাহরণটি সম্পর্কে অবগত তা হ'ল এই দৈর্ঘ্যের ৩১ টি সাপ যা লেম্বিক উল্লেখ করেছিলেন, ডেভিড কেকে ধন্যবাদ :

(1,1,1,1,2,1,2,1,1,1,1,1,1,2,1,1,1,2,1,1,2,2,1,0,1,0,1,1,1,1)

display('111121211111121112112210101111') নিম্নলিখিত আউটপুট দেয়:

প্রতিবেশী না হয়ে সংক্ষিপ্ততম সাপের চিত্র

টিপ: আপনি যদি ডিসপ্লে উইন্ডোটির আকার পরিবর্তন করেন এবং তারপরে আবার ডিসপ্লেতে কল করেন তবে সাপটি নতুন উইন্ডোর আকারের সাথে লাগানো হবে।

প্রতিবেশী না থাকলে কারও সংক্ষিপ্ত উদাহরণ রয়েছে তার কাছ থেকে আমি শুনতে চাই। আমি সন্দেহ করি যে সংক্ষিপ্ততম উদাহরণটি সবচেয়ে ছোট এনটিকে চিহ্নিত করবে যার জন্য দুটি ক্রম পৃথক।


* নোট করুন যে এন এর প্রতিটি বৃদ্ধি প্রায় 3 বার হিসাবে দীর্ঘ সময় নেয়, সুতরাং এন = 11 থেকে এন = 13 এ বাড়তে প্রায় 10 বার সময় প্রয়োজন। এই কারণেই পাইপই কেবল স্ট্যান্ডার্ড পাইথন ইন্টারপ্রেটারের চেয়ে বেশ দ্রুত গতি সঞ্চার করলেও কেবল 2 দ্বারা n বাড়িয়ে দেয়।


6
যদি এই মন্তব্যটি 5 টি আপগেট পায় তবে আমি বিশ্লেষণে সহায়তা করে এমন ক্ষেত্রে সম্ভাব্য বিন্যাসের ভিজ্যুয়ালাইজেশন অন্তর্ভুক্ত করার জন্য একটি বিকল্প যুক্ত করার দিকে নজর দেব।
ট্রাইকপ্লেক্স


@ জিওবাইটস আমি মনে করি এই মুহুর্তে আমি এটি পেয়েছি ...
ট্রাইকোপ্লাক্স


1
@ জাকুব এটি বিভিন্ন উপায়ে উদ্বোধনযোগ্য যেমন অর্ডার জয়েন্ট # 1 # 3 # 2 # 4 # 5 # 6।
এলোমেলো

1

সি ++ 11 - প্রায় কাজ :)

এই নিবন্ধটি পড়ার পরে , আমি সেই লোকটির কাছ থেকে প্রজ্ঞার বিট সংগ্রহ করেছি যিনি স্পষ্টতই একটি বর্গক্ষেত্রের জাল দিয়ে স্ব-পরিহারের পথ গণনা করার কম জটিল সমস্যার জন্য 25 বছর ধরে দৃশ্যত কাজ করেছিলেন।

#include <cassert>
#include <ctime>
#include <sstream>
#include <vector>
#include <algorithm> // sort

using namespace std;

// theroretical max snake lenght (the code would need a few decades to process that value)
#define MAX_LENGTH ((int)(1+8*sizeof(unsigned)))

#ifndef _MSC_VER
#ifndef QT_DEBUG // using Qt IDE for g++ builds
#define NDEBUG
#endif
#endif

#ifdef NDEBUG
inline void tprintf(const char *, ...){}
#else
#define tprintf printf
#endif

void panic(const char * msg)
{
    printf("PANIC: %s\n", msg);
    exit(-1);
}

// ============================================================================
// fast bit reversal
// ============================================================================
unsigned bit_reverse(register unsigned x, unsigned len)
{
    x = (((x & 0xaaaaaaaa) >> 1) | ((x & 0x55555555) << 1));
    x = (((x & 0xcccccccc) >> 2) | ((x & 0x33333333) << 2));
    x = (((x & 0xf0f0f0f0) >> 4) | ((x & 0x0f0f0f0f) << 4));
    x = (((x & 0xff00ff00) >> 8) | ((x & 0x00ff00ff) << 8));
    return((x >> 16) | (x << 16)) >> (32-len);
}

// ============================================================================
// 2D geometry (restricted to integer coordinates and right angle rotations)
// ============================================================================

// points using integer- or float-valued coordinates
template<typename T>struct tTypedPoint;

typedef int    tCoord;
typedef double tFloatCoord;

typedef tTypedPoint<tCoord> tPoint;
typedef tTypedPoint<tFloatCoord>  tFloatPoint;

template <typename T>
struct tTypedPoint {
    T x, y;

    template<typename U> tTypedPoint(const tTypedPoint<U>& from) : x((T)from.x), y((T)from.y) {} // conversion constructor

    tTypedPoint() {}
    tTypedPoint(T x, T y) : x(x), y(y) {}
    tTypedPoint(const tTypedPoint& p) { *this = p; }
    tTypedPoint operator+ (const tTypedPoint & p) const { return{ x + p.x, y + p.y }; }
    tTypedPoint operator- (const tTypedPoint & p) const { return{ x - p.x, y - p.y }; }
    tTypedPoint operator* (T scalar) const { return{ x * scalar, y * scalar }; }
    tTypedPoint operator/ (T scalar) const { return{ x / scalar, y / scalar }; }
    bool operator== (const tTypedPoint & p) const { return x == p.x && y == p.y; }
    bool operator!= (const tTypedPoint & p) const { return !operator==(p); }
    T dot(const tTypedPoint &p) const { return x*p.x + y * p.y; } // dot product  
    int cross(const tTypedPoint &p) const { return x*p.y - y * p.x; } // z component of cross product
    T norm2(void) const { return dot(*this); }

    // works only with direction = 1 (90° right) or -1 (90° left)
    tTypedPoint rotate(int direction) const { return{ direction * y, -direction * x }; }
    tTypedPoint rotate(int direction, const tTypedPoint & center) const { return (*this - center).rotate(direction) + center; }

    // used to compute length of a ragdoll snake segment
    unsigned manhattan_distance(const tPoint & p) const { return abs(x-p.x) + abs(y-p.y); }
};


struct tArc {
    tPoint c;                        // circle center
    tFloatPoint middle_vector;       // vector splitting the arc in half
    tCoord      middle_vector_norm2; // precomputed for speed
    tFloatCoord dp_limit;

    tArc() {}
    tArc(tPoint c, tPoint p, int direction) : c(c)
    {
        tPoint r = p - c;
        tPoint end = r.rotate(direction);
        middle_vector = ((tFloatPoint)(r+end)) / sqrt(2); // works only for +-90° rotations. The vector should be normalized to circle radius in the general case
        middle_vector_norm2 = r.norm2();
        dp_limit = ((tFloatPoint)r).dot(middle_vector);
        assert (middle_vector == tPoint(0, 0) || dp_limit != 0);
    }

    bool contains(tFloatPoint p) // p must be a point on the circle
    {
        if ((p-c).dot(middle_vector) >= dp_limit)
        {
            return true;
        }
        else return false;
    }
};

// returns the point of line (p1 p2) that is closest to c
// handles degenerate case p1 = p2
tPoint line_closest_point(tPoint p1, tPoint p2, tPoint c)
{
    if (p1 == p2) return{ p1.x, p1.y };
    tPoint p1p2 = p2 - p1;
    tPoint p1c =  c  - p1;
    tPoint disp = (p1p2 * p1c.dot(p1p2)) / p1p2.norm2();
    return p1 + disp;
}

// variant of closest point computation that checks if the projection falls within the segment
bool closest_point_within(tPoint p1, tPoint p2, tPoint c, tPoint & res)
{
    tPoint p1p2 = p2 - p1;
    tPoint p1c = c - p1;
    tCoord nk = p1c.dot(p1p2);
    if (nk <= 0) return false;
    tCoord n = p1p2.norm2();
    if (nk >= n) return false;
    res = p1 + p1p2 * (nk / n);
    return true;
}

// tests intersection of line (p1 p2) with an arc
bool inter_seg_arc(tPoint p1, tPoint p2, tArc arc)
{
    tPoint m = line_closest_point(p1, p2, arc.c);
    tCoord r2 = arc.middle_vector_norm2;
    tPoint cm = m - arc.c;
    tCoord h2 = cm.norm2();
    if (r2 < h2) return false; // no circle intersection

    tPoint p1p2 = p2 - p1;
    tCoord n2p1p2 = p1p2.norm2();

    // works because by construction p is on (p1 p2)
    auto in_segment = [&](const tFloatPoint & p) -> bool
    {
        tFloatCoord nk = p1p2.dot(p - p1);
        return nk >= 0 && nk <= n2p1p2;
    };

    if (r2 == h2) return arc.contains(m) && in_segment(m); // tangent intersection

    //if (p1 == p2) return false; // degenerate segment located inside circle
    assert(p1 != p2);

    tFloatPoint u = (tFloatPoint)p1p2 * sqrt((r2-h2)/n2p1p2); // displacement on (p1 p2) from m to one intersection point

    tFloatPoint i1 = m + u;
    if    (arc.contains(i1) && in_segment(i1)) return true;
    tFloatPoint i2 = m - u;
    return arc.contains(i2) && in_segment(i2);
}

// ============================================================================
// compact storage of a configuration (64 bits)
// ============================================================================
struct sConfiguration {
    unsigned partition;
    unsigned folding;

    explicit sConfiguration() {}
    sConfiguration(unsigned partition, unsigned folding) : partition(partition), folding(folding) {}

    // add a bend
    sConfiguration bend(unsigned joint, int rotation) const
    {
        sConfiguration res;
        unsigned joint_mask = 1 << joint;
        res.partition = partition | joint_mask;
        res.folding = folding;
        if (rotation == -1) res.folding |= joint_mask;
        return res;
    }

    // textual representation
    string text(unsigned length) const
    {
        ostringstream res;

        unsigned f = folding;
        unsigned p = partition;

        int segment_len = 1;
        int direction = 1;
        for (size_t i = 1; i != length; i++)
        {
            if (p & 1)
            {
                res << segment_len * direction << ',';
                direction = (f & 1) ? -1 : 1;
                segment_len = 1;
            }
            else segment_len++;

            p >>= 1;
            f >>= 1;
        }
        res << segment_len * direction;
        return res.str();
    }

    // for final sorting
    bool operator< (const sConfiguration& c) const
    {
        return (partition == c.partition) ? folding < c.folding : partition < c.partition;
    }
};

// ============================================================================
// static snake geometry checking grid
// ============================================================================
typedef unsigned tConfId;

class tGrid {
    vector<tConfId>point;
    tConfId current;
    size_t snake_len;
    int min_x, max_x, min_y, max_y;
    size_t x_size, y_size;

    size_t raw_index(const tPoint& p) { bound_check(p);  return (p.x - min_x) + (p.y - min_y) * x_size; }
    void bound_check(const tPoint& p) const { assert(p.x >= min_x && p.x <= max_x && p.y >= min_y && p.y <= max_y); }

    void set(const tPoint& p)
    {
        point[raw_index(p)] = current;
    }
    bool check(const tPoint& p)
    {
        if (point[raw_index(p)] == current) return false;
        set(p);
        return true;
    }

public:
    tGrid(int len) : current(-1), snake_len(len)
    {
        min_x = -max(len - 3, 0);
        max_x = max(len - 0, 0);
        min_y = -max(len - 1, 0);
        max_y = max(len - 4, 0);
        x_size = max_x - min_x + 1;
        y_size = max_y - min_y + 1;
        point.assign(x_size * y_size, current);
    }

    bool check(sConfiguration c)
    {
        current++;
        tPoint d(1, 0);
        tPoint p(0, 0);
        set(p);
        for (size_t i = 1; i != snake_len; i++)
        {
            p = p + d;
            if (!check(p)) return false;
            if (c.partition & 1) d = d.rotate((c.folding & 1) ? -1 : 1);
            c.folding >>= 1;
            c.partition >>= 1;
        }
        return check(p + d);
    }

};

// ============================================================================
// snake ragdoll 
// ============================================================================
class tSnakeDoll {
    vector<tPoint>point; // snake geometry. Head at (0,0) pointing right

    // allows to check for collision with the area swept by a rotating segment
    struct rotatedSegment {
        struct segment { tPoint a, b; };
        tPoint  org;
        segment end;
        tArc    arc[3];
        bool extra_arc; // see if third arc is needed

        // empty constructor to avoid wasting time in vector initializations
        rotatedSegment(){}
        // copy constructor is mandatory for vectors *but* shall never be used, since we carefully pre-allocate vector memory
        rotatedSegment(const rotatedSegment &){ assert(!"rotatedSegment should never have been copy-constructed"); }

        // rotate a segment
        rotatedSegment(tPoint pivot, int rotation, tPoint o1, tPoint o2)
        {
            arc[0] = tArc(pivot, o1, rotation);
            arc[1] = tArc(pivot, o2, rotation);
            tPoint middle;
            extra_arc = closest_point_within(o1, o2, pivot, middle);
            if (extra_arc) arc[2] = tArc(pivot, middle, rotation);
            org = o1;
            end = { o1.rotate(rotation, pivot), o2.rotate(rotation, pivot) };
        }

        // check if a segment intersects the area swept during rotation
        bool intersects(tPoint p1, tPoint p2) const
        {
            auto print_arc = [&](int a) { tprintf("(%d,%d)(%d,%d) -> %d (%d,%d)[%f,%f]", p1.x, p1.y, p2.x, p2.y, a, arc[a].c.x, arc[a].c.y, arc[a].middle_vector.x, arc[a].middle_vector.y); };

            if (p1 == org) return false; // pivot is the only point allowed to intersect
            if (inter_seg_arc(p1, p2, arc[0])) 
            { 
                print_arc(0);  
                return true;
            }
            if (inter_seg_arc(p1, p2, arc[1]))
            { 
                print_arc(1); 
                return true;
            }
            if (extra_arc && inter_seg_arc(p1, p2, arc[2])) 
            { 
                print_arc(2);
                return true;
            }
            return false;
        }
    };

public:
    sConfiguration configuration;
    bool valid;

    // holds results of a folding attempt
    class snakeFolding {
        friend class tSnakeDoll;
        vector<rotatedSegment>segment; // rotated segments
        unsigned joint;
        int direction;
        size_t i_rotate;

        // pre-allocate rotated segments
        void reserve(size_t length)
        {
            segment.clear(); // this supposedly does not release vector storage memory
            segment.reserve(length);
        }

        // handle one segment rotation
        void rotate(tPoint pivot, int rotation, tPoint o1, tPoint o2)
        {
            segment.emplace_back(pivot, rotation, o1, o2);
        }
    public:
        // nothing done during construction
        snakeFolding(unsigned size)
        {
            segment.reserve (size);
        }
    };

    // empty default constructor to avoid wasting time in array/vector inits
    tSnakeDoll() {}

    // constructs ragdoll from compressed configuration
    tSnakeDoll(unsigned size, unsigned generator, unsigned folding) : point(size), configuration(generator,folding)
    {
        tPoint direction(1, 0);
        tPoint current = { 0, 0 };
        size_t p = 0;
        point[p++] = current;
        for (size_t i = 1; i != size; i++)
        {
            current = current + direction;
            if (generator & 1)
            {
                direction.rotate((folding & 1) ? -1 : 1);
                point[p++] = current;
            }
            folding >>= 1;
            generator >>= 1;
        }
        point[p++] = current;
        point.resize(p);
    }

    // constructs the initial flat snake
    tSnakeDoll(int size) : point(2), configuration(0,0), valid(true)
    {
        point[0] = { 0, 0 };
        point[1] = { size, 0 };
    }

    // constructs a new folding with one added rotation
    tSnakeDoll(const tSnakeDoll & parent, unsigned joint, int rotation, tGrid& grid)
    {
        // update configuration
        configuration = parent.configuration.bend(joint, rotation);

        // locate folding point
        unsigned p_joint = joint+1;
        tPoint pivot;
        size_t i_rotate = 0;
        for (size_t i = 1; i != parent.point.size(); i++)
        {
            unsigned len = parent.point[i].manhattan_distance(parent.point[i - 1]);
            if (len > p_joint)
            {
                pivot = parent.point[i - 1] + ((parent.point[i] - parent.point[i - 1]) / len) * p_joint;
                i_rotate = i;
                break;
            }
            else p_joint -= len;
        }

        // rotate around joint
        snakeFolding fold (parent.point.size() - i_rotate);
        fold.rotate(pivot, rotation, pivot, parent.point[i_rotate]);
        for (size_t i = i_rotate + 1; i != parent.point.size(); i++) fold.rotate(pivot, rotation, parent.point[i - 1], parent.point[i]);

        // copy unmoved points
        point.resize(parent.point.size()+1);
        size_t i;
        for (i = 0; i != i_rotate; i++) point[i] = parent.point[i];

        // copy rotated points
        for (; i != parent.point.size(); i++) point[i] = fold.segment[i - i_rotate].end.a;
        point[i] = fold.segment[i - 1 - i_rotate].end.b;

        // static configuration check
        valid = grid.check (configuration);

        // check collisions with swept arcs
        if (valid && parent.valid) // ;!; parent.valid test is temporary
        {
            for (const rotatedSegment & s : fold.segment)
            for (size_t i = 0; i != i_rotate; i++)
            {
                if (s.intersects(point[i+1], point[i]))
                {
                    //printf("! %s => %s\n", parent.trace().c_str(), trace().c_str());//;!;
                    valid = false;
                    break;
                }
            }
        }
    }

    // trace
    string trace(void) const
    {
        size_t len = 0;
        for (size_t i = 1; i != point.size(); i++) len += point[i - 1].manhattan_distance(point[i]);
        return configuration.text(len);
    }
};

// ============================================================================
// snake twisting engine
// ============================================================================
class cSnakeFolder {
    int length;
    unsigned num_joints;
    tGrid grid;

    // filter redundant configurations
    bool is_unique (sConfiguration c)
    {
        unsigned reverse_p = bit_reverse(c.partition, num_joints);
        if (reverse_p < c.partition)
        {
            tprintf("P cut %s\n", c.text(length).c_str());
            return false;
        }
        else if (reverse_p == c.partition) // filter redundant foldings
        {
            unsigned first_joint_mask = c.partition & (-c.partition); // insulates leftmost bit
            unsigned reverse_f = bit_reverse(c.folding, num_joints);
            if (reverse_f & first_joint_mask) reverse_f = ~reverse_f & c.partition;

            if (reverse_f > c.folding)
            {
                tprintf("F cut %s\n", c.text(length).c_str());
                return false;
            }
        }
        return true;
    }

    // recursive folding
    void fold(tSnakeDoll snake, unsigned first_joint)
    {
        // count unique configurations
        if (snake.valid && is_unique(snake.configuration)) num_configurations++;

        // try to bend remaining joints
        for (size_t joint = first_joint; joint != num_joints; joint++)
        {
            // right bend
            tprintf("%s -> %s\n", snake.configuration.text(length).c_str(), snake.configuration.bend(joint,1).text(length).c_str());
            fold(tSnakeDoll(snake, joint, 1, grid), joint + 1);

            // left bend, except for the first joint
            if (snake.configuration.partition != 0)
            {
                tprintf("%s -> %s\n", snake.configuration.text(length).c_str(), snake.configuration.bend(joint, -1).text(length).c_str());
                fold(tSnakeDoll(snake, joint, -1, grid), joint + 1);
            }
        }
    }

public:
    // count of found configurations
    unsigned num_configurations;

    // constructor does all the work :)
    cSnakeFolder(int n) : length(n), grid(n), num_configurations(0)
    {
        num_joints = length - 1;

        // launch recursive folding
        fold(tSnakeDoll(length), 0);
    }
};

// ============================================================================
// here we go
// ============================================================================
int main(int argc, char * argv[])
{
#ifdef NDEBUG
    if (argc != 2) panic("give me a snake length or else");
    int length = atoi(argv[1]);
#else
    (void)argc; (void)argv;
    int length = 12;
#endif // NDEBUG

    if (length <= 0 || length >= MAX_LENGTH) panic("a snake of that length is hardly foldable");

    time_t start = time(NULL);
    cSnakeFolder snakes(length);
    time_t duration = time(NULL) - start;

    printf ("Found %d configuration%c of length %d in %lds\n", snakes.num_configurations, (snakes.num_configurations == 1) ? '\0' : 's', length, duration);
    return 0;
}

এক্সিকিউটেবল বিল্ডিং

"লিনাক্স" তৈরির জন্য উইন 7 এর সাথে আমি জি ++ 4.8 এর সাথে মিনজিডাব্লু ব্যবহার করে সংকলন করুন, সুতরাং বহনযোগ্যতা 100% গ্যারান্টিযুক্ত নয়।g++ -O3 -std=c++11

এটি একটি স্ট্যান্ডার্ড এমএসভিসি ২০১৩ প্রকল্পের সাথে (সাজানোর) কাজ করে

অপরিবর্তিত করে NDEBUG, আপনি অ্যালগরিদম সম্পাদনার চিহ্ন এবং পাওয়া কনফিগারেশনের সংক্ষিপ্তসার পাবেন।

ক্রিয়াকাণ্ড

হ্যাশ টেবিলগুলি সহ বা ছাড়াই, মাইক্রোসফ্ট সংকলক খারাপভাবে সঞ্চালন করে: g ++ বিল্ডটি 3 গুণ দ্রুত

অ্যালগরিদম ব্যবহারিকভাবে কোনও মেমরি ব্যবহার করে না।

যেহেতু সংঘর্ষের চেকটি মোটামুটি ও (এন) এ, তাই গণনার সময় ও ( এন কে এন ) এ হওয়া উচিত ,
কেটি 3 এর চেয়ে সামান্য কম my আমার i3-2100@3.1GHz এ, n = 17 লাগে প্রায় 1:30 (প্রায় 2 মিলিয়ন) সাপ / মিনিট)।

আমি অপ্টিমাইজিং সম্পন্ন করিনি, তবে আমি x3 লাভের বেশি আশা করব না, তাই মূলত আমি এক ঘন্টার মধ্যে n = 20, বা এক দিনের মধ্যে n = 24 পৌঁছানোর আশা করতে পারি।

বিদ্যুৎ বিভ্রাটকে ধরে না রেখে প্রথম পরিচিত অনিবার্য আকারে পৌঁছতে (n = 31) কয়েক বছর এবং এক দশকের মধ্যে সময় লাগবে।

আকার গণনা করা হচ্ছে

একটি এন আকারের সাপটিতে এন -1 জয়েন্ট রয়েছে।
প্রতিটি যৌথ সরাসরি বা বাম বা ডান দিকে বাঁকানো যেতে পারে (3 সম্ভাবনা)।
সম্ভাব্য ভাঁজ সংখ্যা এইভাবে 3 এন -1
সংঘর্ষগুলি এই সংখ্যাটি কিছুটা কমিয়ে দেবে, তাই আসল সংখ্যাটি 2.7 এন -1 এর কাছাকাছি

যাইহোক, এই জাতীয় অনেকগুলি ভাঁজগুলি অভিন্ন আকারে বাড়ে।

দুটি আবর্ত একরকম হয় যদি কোনও ঘূর্ণন বা একটি প্রতিসাম্য থাকে যা একটিতে অন্যকে রূপান্তর করতে পারে।

ভাঁজ করা শরীরের কোনও সরাসরি অংশ হিসাবে একটি বিভাগকে সংজ্ঞায়িত করি ।
উদাহরণস্বরূপ 2 য় সংযুক্তে ভাঁজ করা একটি আকারের 5 টি সাপের 2 টি অংশ থাকবে (একটি 2 ইউনিট দীর্ঘ এবং দ্বিতীয় 3 ইউনিট দীর্ঘ)।
প্রথম বিভাগটির নাম দেওয়া হবে মাথা , এবং শেষ লেজ

কনভেনশন দ্বারা আমরা সাপগুলির মাথাটি অনুভূমিকভাবে দেহকে নির্দেশ করে দেহের সাথে ডানদিকে নির্দেশ করি (যেমন প্রথম ওপেনের প্রথম চিত্রটিতে)।

আমরা স্বাক্ষরিত সেগমেন্ট দৈর্ঘ্যের একটি তালিকা সহ একটি প্রদত্ত চিত্রকে মনোনীত করি, ধনাত্মক দৈর্ঘ্যের সাথে ডান ভাঁজ এবং নেতিবাচকগুলিকে বাম ভাঁজ নির্দেশ করে।
প্রাথমিক দৈর্ঘ্য কনভেনশন দ্বারা ইতিবাচক।

বিভাগগুলি এবং মোড়গুলি পৃথক করে

যদি আমরা কেবলমাত্র দৈর্ঘ্যের N এর একটি সাপকে বিভাগগুলিতে বিভক্ত করা যায় তার জন্য বিভিন্ন উপায় বিবেচনা করি, তবে আমরা N এর রচনাগুলির মতো একটি পুনরায় বিভাজন শেষ করি

উইকির পৃষ্ঠাতে প্রদর্শিত একই অ্যালগরিদম ব্যবহার করে , সাপের সমস্ত 2 এন -1 সম্ভাব্য পার্টিশন উত্পন্ন করা সহজ ।

প্রতিটি পার্টিশন ঘুরে তার সমস্ত জয়েন্টগুলিতে বাম বা ডান বাঁক প্রয়োগ করে সমস্ত সম্ভাব্য ভাঁজ তৈরি করবে। এই ধরনের একটি ভাঁজ একটি ডাকা হবে কনফিগারেশন

সমস্ত সম্ভাব্য পার্টিশন N-1 বিটের পূর্ণসংখ্যার দ্বারা প্রতিনিধিত্ব করা যেতে পারে, যেখানে প্রতিটি বিট একটি জয়েন্টের উপস্থিতি উপস্থাপন করে। আমরা এই পূর্ণসংখ্যাটিকে একটি জেনারেটর বলব

পার্টিশন ছাঁটাই

মাথা থেকে নীচে প্রদত্ত পার্টিশনটি বাঁকানো লেজটি থেকে সিমেট্রিকাল পার্টিশনটি বাঁকানোর সমতুল্য তা লক্ষ্য করে, আমরা প্রতিযোগিতামূলক পার্টিশনের সমস্ত দম্পতি খুঁজে পেতে পারি এবং দুটির মধ্যে একটি অপসারণ করতে পারি।
একটি সিমেট্রিকাল পার্টিশনের জেনারেটর হ'ল বিপরীতে বিট অর্ডারে লেখা পার্টিশনের জেনারেটর, যা তুচ্ছভাবে সনাক্ত করা সহজ এবং সস্তা।

এটি সম্ভাব্য পার্টিশনের প্রায় অর্ধেকটি কেটে ফেলবে, ব্যতিক্রমগুলি "প্যালিনড্রমিক" জেনারেটরগুলির সাথে পার্টিশনগুলি বাদ দেয় যা কিছুটা বিপরীতমুখী হয়ে থাকে (উদাহরণস্বরূপ 00100100)।

অনুভূমিক symetries যত্ন নেওয়া

আমাদের কনভেনশনগুলির সাথে (একটি সাপ ডান দিকে নির্দেশ করতে শুরু করে), ডানদিকে প্রয়োগ করা খুব প্রথম বাঁকটি ভাঁজের একটি পরিবার তৈরি করবে যা কেবল প্রথম বাঁক দ্বারা পৃথক হওয়াগুলির চেয়ে অনুভূমিক প্রতিলিপি হবে।

যদি আমরা স্থির করি যে প্রথম বাঁকটি সর্বদা ডানদিকে থাকবে, আমরা একটি বড় সাঁকোতে সমস্ত অনুভূমিক সিনমেট্রিকগুলি মুছে ফেলি।

প্যালিনড্রোমগুলি প্রস্তুত করা

এই দুটি কাটা দক্ষ, কিন্তু এই pesky প্যালিনড্রোম যত্ন নিতে যথেষ্ট নয়।
সাধারণ ক্ষেত্রে সবচেয়ে পুঙ্খানুপুঙ্খ চেকটি নিম্নরূপ:

একটি প্যালিনড্রমিক পার্টিশন সহ একটি কনফিগারেশন সি বিবেচনা করুন।

  • যদি আমরা invert সি প্রত্যেক মোড়, আমরা সি এর একটি অনুভূমিক symetric দিয়ে শেষ
  • যদি আমরা সিটিকে বিপরীত করি (লেজটি উপরে বাঁক প্রয়োগ করে), আমরা একই চিত্রটি ডানদিকে ঘোরাই
  • যদি আমরা উভয়ই বিপরীত ও উল্টে করি তবে আমরা একই চিত্রটি বাম দিকে ঘোরাই।

আমরা অন্য 3 জনের বিরুদ্ধে প্রতিটি নতুন কনফিগারেশন চেক করতে পারি। তবে, যেহেতু আমরা ইতিমধ্যে কেবল ডান ঘুরিয়ে দিয়ে শুরু হওয়া কনফিগারেশনগুলি তৈরি করেছি, আমাদের চেক করার জন্য কেবল একটি সম্ভাব্য সিমেট্রি রয়েছে:

  • উল্টানো সিটি বাম বাঁক দিয়ে শুরু হবে, যা নির্মাণের মাধ্যমে অনুলিপি করা সম্ভব নয়
  • বিপরীত এবং উল্টানো-বিপরীত কনফিগারেশনগুলির মধ্যে, কেবলমাত্র একটি ডান মোড় দিয়ে শুরু হবে।
    এটিই কেবলমাত্র একটি কনফিগারেশন যা আমরা সম্ভবত নকল করতে পারি।

কোনও স্টোরেজ ছাড়াই ডুপ্লিকেটগুলি মুছে ফেলা হচ্ছে

আমার প্রাথমিক পদ্ধতির ছিল সমস্ত কনফিগারেশনগুলি একটি বিশাল হ্যাশ টেবিলের মধ্যে সংরক্ষণ করা, পূর্বে গণনা করা সিমেট্রিক কনফিগারেশনের উপস্থিতি পরীক্ষা করে নকলকে সরিয়ে ফেলা।

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

সুতরাং, সদৃশ জন্য একটি কনফিগারেশন পরীক্ষা সিমেট্রিক পার্টিশন গণনা সমান, এবং যদি উভয় অভিন্ন, ভাঁজ। কোনও স্মৃতির দরকার নেই।

প্রজন্মের অর্ডার

স্পষ্টতই সংঘর্ষের চেকটি সবচেয়ে বেশি সময় ব্যয়কারী অংশ হবে, সুতরাং এই গুণাগুণ হ্রাস করা একটি বড় সময় সাশ্রয়কারী।

একটি সম্ভাব্য সমাধান হ'ল একটি "র‌্যাডল সাপ" যা ফ্ল্যাট কনফিগারেশনে শুরু হবে এবং ধীরে ধীরে বাঁকানো হবে, প্রতিটি সম্ভাব্য কনফিগারেশনের জন্য পুরো সাপের জ্যামিতিকে পুনর্নির্মাণ এড়াতে।

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

আমি লেজ থেকে নীচে একটি পুনরাবৃত্ত স্ক্যান ব্যবহার, প্রতিটি স্তরে একক যৌথ যোগ। এইভাবে একটি নতুন অ্যাডিশনাল বাঁক সহ প্যারেন্ট কনফিগারেশনের উপরে একটি নতুন র‌্যাডল দৃষ্টান্ত তৈরি করা হয়।

এর অর্থ, মোড়গুলি ক্রমিক ক্রমে প্রয়োগ করা হয়, যা প্রায় সমস্ত ক্ষেত্রেই আত্ম-সংঘর্ষ এড়াতে যথেষ্ট বলে মনে হয়।

যখন আত্ম-সংঘর্ষ শনাক্ত করা যায়, আপত্তিজনক পদক্ষেপের দিকে পরিচালিত বাঁকগুলি লাইট ফোল্ডিং না পাওয়া বা সমস্ত সংমিশ্রণ শেষ না হওয়া অবধি সমস্ত সম্ভাব্য অর্ডারে প্রয়োগ করা হয়।

স্থির চেক

এমনকি অংশগুলি চলন্ত সম্পর্কে চিন্তা করার আগে, আমি নিজেকে ছেদ করার জন্য একটি সাপের স্থির চূড়ান্ত আকার পরীক্ষা করতে আরও দক্ষ বলে মনে করেছি।

একটি গ্রিডে সাপ আঁকিয়ে এটি করা হয়। প্রতিটি সম্ভাব্য পয়েন্ট মাথা থেকে নিচে চক্রান্ত করা হয়। যদি কোনও স্ব-ছেদটি থাকে, তবে কমপক্ষে একটি পয়েন্টের জোড়া একই জায়গায় পড়বে। ধ্রুবক ও (এন) সময়ের জন্য এটি কোনও সাপের কনফিগারেশনের জন্য ঠিক এন প্লটগুলির প্রয়োজন।

এই পদ্ধতির মূল সুবিধা হ'ল একা স্থির পরীক্ষাটি কেবল একটি বর্গক্ষেত্রের জালিতে বৈধ স্ব-পরিহারের পাথগুলি বেছে নেবে যা গতিশীল সংঘর্ষ সনাক্তকরণকে বাধা দিয়ে এবং এই জাতীয় পাথগুলির সঠিক গণনা খুঁজে পেয়েছে তা নিশ্চিত করে পুরো অ্যালগরিদমকে পরীক্ষা করার অনুমতি দেয়।

গতিশীল চেক

যখন একটি সাপ একটি জয়েন্টের চারপাশে ভাঁজ হয়, প্রতিটি ঘোরানো অংশটি এমন একটি অঞ্চলকে ছড়িয়ে দেবে যার আকার তুচ্ছ ছাড়া কিছু নয়।
স্পষ্টতই আপনি স্বতঃস্ফূর্তভাবে এই সমস্ত বিচ্ছিন্ন অঞ্চলের অন্তর্ভুক্তি পরীক্ষা করে সংঘর্ষগুলি চেক করতে পারেন। একটি গ্লোবাল চেক আরও দক্ষ হবে, তবে অঞ্চলগুলির জটিলতার কারণে আমি কোনওটিই ভাবতে পারি না (সম্ভবত কোনও জিপিইউ ব্যবহার করে সমস্ত অঞ্চল আঁকতে এবং বিশ্বব্যাপী হিট চেক সম্পাদন করতে পারেন)।

যেহেতু স্ট্যাটিক পরীক্ষা প্রতিটি বিভাগের শুরু এবং শেষের অবস্থানগুলি যত্ন করে, তাই আমাদের কেবল প্রতিটি ঘোরানো বিভাগ দ্বারা আর্কে দিয়ে বিভক্ত ছেদগুলি পরীক্ষা করা দরকার ।

আমার বিয়ারিংগুলি পেতে ট্রাইকপ্লেক্স এবং জাভা স্ক্রিপ্টের সাথে একটি আকর্ষণীয় আলোচনার পরে , আমি এই পদ্ধতিটি নিয়ে এসেছি:

যদি আপনি কল করেন তবে কয়েকটি কথায় এটি দেওয়ার চেষ্টা করুন

  • সি আবর্তনের কেন্দ্র,
  • এস বিচ্ছিন্ন দৈর্ঘ্য এবং দিকের একটি ঘূর্ণায়মান বিভাগ যা সি ধারণ করে না ,
  • এল লাইন দীর্ঘায়িত এস
  • এইচ লাইন লম্ব এল মাধ্যমে ক্ষণস্থায়ী সি ,
  • আমি এল এবং এইচ এর ছেদ ,

গণিতশাস্ত্র
(উত্স: free.fr )

কোন অংশ যা ধারণ করে না জন্য আমি , মোটামুটি এলাকায় 2 পরিধির মধ্যে (এবং 2 অংশ ইতিমধ্যে স্ট্যাটিক চেকের মাধ্যমে যত্ন গ্রহণ) দ্বারা আবদ্ধ করা হয়।

আমি যদি সেগমেন্টের মধ্যে পড়ে যাই , আমার দ্বারা অর্পিত আর্কটিও আমলে নেওয়া উচিত।

এর অর্থ আমরা প্রতিটি ঘুরানো বিভাগের বিপরীতে 2 বা 3 টি বিভাগের সাথে-মোড় দিয়ে ছেদ করতে পারি

আমি পুরোপুরি ত্রিকোণমিতিক কার্যগুলি এড়াতে ভেক্টর জ্যামিতি ব্যবহার করেছি।
ভেক্টর অপারেশনগুলি কমপ্যাক্ট এবং (তুলনামূলকভাবে) পঠনযোগ্য কোড উত্পাদন করে।

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

এটা কি কাজ করে?

গতিশীল সংঘর্ষ শনাক্তকরণকে বাধা দেওয়া সঠিক এন-এফ-এড়িং পাথগুলি n = 19 পর্যন্ত গণনা করে, তাই আমি বিশ্বস্ত লেআউটটি কার্যকরভাবে যথেষ্ট আত্মবিশ্বাসী।

গতিশীল সংঘর্ষ সনাক্তকরণটি ধারাবাহিক ফলাফলগুলি তৈরি করে, যদিও বিভিন্ন ক্রমে বেন্ডের চেকটি অনুপস্থিত (বর্তমানে জন্য)।
ফলস্বরূপ, প্রোগ্রামটি এমন সাপকে গণনা করে যা মাথা থেকে নীচে বাঁকানো যায় (অর্থাত্ মাথা থেকে দূরত্ব বাড়ানোর ক্রমযুক্ত জোড়গুলি দিয়ে)।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.