POJ-2286 The Rotation Game + Python(DFS)

Posted by chadtimothy23 on Sun, 26 Dec 2021 15:03:44 +0100

Title Link: poj 2286 The Rotation Game

Title Purpose: make the values of the middle 8 elements the same by rotating in 8 directions. Examples are as follows:

I. problem solving instructions

#1 note: during Rotation, the matrix data needs to be re assigned, otherwise it will change together.
#2. Note: the operation procedure is stored in a queue. When assigning a queue to a new queue, you need to pay special attention to the order of elements in the queue, because it corresponds to the operation order.

                 new_step = []
                 new_step.append(dir_i)
                 for step_i in step:
                     new_step.append(step_i)
                 # Ensure that the order cannot be changed, otherwise the order will be wrong when the final output is made
                 new_step.append(dir_i) # Add at tail
                 # And remove the data of the head
                 new_step.pop(0)

# Set the number corresponding to each operation in advance:
# Set operation flag
action = {0:['A'],1:['B'],2:['C'],3:['D'],4:['E'],5:['F'],6:['G'],7:['H']}

#3. Determination of target elements: count the number of 1 / 2 / 3 three elements in the target area, and take the element corresponding to the largest number as the target element. See findTarget function
#4 some rules:
#4.1 if the target element changes after one rotation, return
#4.2 after one rotation, if the target element does not change but the number decreases, return
#4.3 after one rotation, if the target elements do not change and the number does not decrease, enter the next dfs search;
#5 termination conditions
#5.1 the number of target elements in the target area is 8. return successfully!
#5.1. 1. Save the current scheme
#5.1. 2 store the current target element
#5.2 if the DFS search depth is greater than the set value, an error return s.
#5.3 assuming that the current target element can find a feasible scheme, other target elements will not be searched.
#5.4 analyze all schemes of the current target element and select the scheme with the shortest length and sorted alphabetically.
#5.4. 1. Each operation is represented in Arabic numerals, the feasible scheme is spliced into a string, and the scheme with the smallest alphabetical order is determined according to the number size corresponding to the string.

II. Code implementation:

# http://www.mianshigee.com/question/16649hrq
import collections
import math

#1 note: during Rotation, the matrix data needs to be re assigned, otherwise it will change together.
#2. Precautions: use the queue to store the operation process. When assigning a queue to a new queue, you need to pay special attention to the order of elements in the queue, because it corresponds to the operation order.
                # new_step = []
                # new_step.append(dir_i)
                # for step_i in step:
                #     new_step.append(step_i)
                # # Ensure that the order cannot be changed, otherwise the order will be wrong when the final output is made
                # new_step.append(dir_i) # Add at tail
                # # And remove the data of the head
                # new_step.pop(0)
#3. Determination of target elements: count the number of 1 / 2 / 3 three elements in the target area, and take the element corresponding to the largest number as the target element. See findTarget function
#4 some rules:
#4.1 if the target element changes after one rotation, return
#4.2 after one rotation, if the target element does not change but the number decreases, return
#4.3 after one rotation, if the target elements do not change and the number does not decrease, enter the next dfs search;
#5 termination conditions
#5.1 the number of target elements in the target area is 8. return successfully!
#5.1. 1. Save the current scheme
#5.1. 2 store the current target element
#5.2 If DFS If the search depth is greater than the set value, an error occurs return. // self.MaxDeep = 4 # this data is particularly effective and helps to improve the execution speed of the algorithm.
#5.3 assuming that the current target element can find a feasible scheme, other target elements will not be searched.
#5.4 analyze all schemes of the current target element and select the scheme with the shortest length and sorted alphabetically.
#5.4. 1. Each operation is represented in Arabic numerals, the feasible scheme is spliced into a string, and the scheme with the smallest alphabetical order is determined according to the number size corresponding to the string.


# Convert data to matrix
def data2Matrix(subData):
    newData = [[0]*7 for i in range(7)]
    # Fill the data of subData into
    for i in range(24):
        if i == 0:
            newData[0][2] = subData[i]
        elif i == 1:
            newData[0][4] = subData[i]
        elif i == 2:
            newData[1][2] = subData[i]
        elif i == 3:
            newData[1][4] = subData[i]
        elif 4<=i<=10:
            newData[2][i-4] = subData[i]
        elif i ==11:
            newData[3][2] = subData[i]
        elif i == 12:
            newData[3][4] = subData[i]
        elif 13<=i<=19:
            newData[4][i-13] = subData[i]
        elif i == 20:
            newData[5][2] = subData[i]
        elif i == 21:
            newData[5][4] = subData[i]
        elif i == 22:
            newData[6][2] = subData[i]
        elif i == 23:
            newData[6][4] = subData[i]
    return newData
# Find the elements of the target area and sort them
def findTarget(subData):
    # Count the number of each element
    num1 = 0
    num2 = 0
    num3 = 0
    # List of coordinates for a given target area
    Target_areas = [[2,2],[2,3],[2,4],[3,2],[3,4],[4,2],[4,3],[4,4]]
    # res = ''#Store data
    for i in range(8):
        rr,cc = Target_areas[i][0],Target_areas[i][1]
        # res = res + str(newData[rr][cc])
        if subData[rr][cc] == 1:
            num1 = num1 + 1
        elif subData[rr][cc] == 2:
            num2 = num2 + 1
        elif subData[rr][cc] == 3:
            num3 = num3 + 1
    ans = [num1,num2,num3]
    min_ans = min(ans)
    max_ans = max(ans)
    targetdict = {}
    for i in range(1,4,1):
        if ans[i-1] == max_ans and 'max' not in targetdict.keys():
            targetdict['max'] = [i,max_ans] # Description of archived data [element value, element quantity]
        elif ans[i-1] == min_ans and 'min' not in targetdict.keys():
            targetdict['min'] = [i, min_ans]
        else:
            targetdict['mid'] = [i, ans[i-1]]
    return targetdict
# Set the rotation and return the rotated matrix and the dictionary of the target area
def Rotation(Data,dir):
    # Data needs to be transferred
    subData = []

    for i in range(len(Data)):
        temp = []
        for j in range(len(Data[0])):
            temp.append(Data[i][j])
        subData.append(temp)

    if dir == 0: #Rotate 1 time in 0 direction
        temp = subData[0][2]
        for i in range(7):
            if i == 6:
                subData[i][2] = temp
            else:
                subData[i][2] = subData[i+1][2]
    elif dir == 1: #Rotate once in direction 1
        temp = subData[0][4]
        for i in range(7):
            if i == 6:
                subData[i][4] = temp
            else:
                subData[i][4] = subData[i+1][4]
    elif dir == 2:
        temp = subData[2][6]
        for i in range(6,-1,-1):
            if i == 0:
                subData[2][0] = temp
            else:
                subData[2][i] = subData[2][i-1]
    elif dir == 3:
        temp = subData[4][6]
        for i in range(6,-1,-1):
            if i == 0:
                subData[4][0] = temp
            else:
                subData[4][i] = subData[4][i-1]
    elif dir == 4:
        temp = subData[6][4]
        for i in range(6,-1,-1):
            if i == 0:
                subData[0][4] = temp
            else:
                subData[i][4] = subData[i - 1][4]
    elif dir == 5:
        temp = subData[6][2]
        for i in range(6,-1,-1):
            if i == 0:
                subData[0][2] = temp
            else:
                subData[i][2] = subData[i - 1][2]
    elif dir == 6:
        temp = subData[4][0]
        for i in range(7):
            if i == 6:
                subData[4][6] = temp
            else:
                subData[4][i] = subData[4][i+1]
    elif dir == 7:
        temp = subData[2][0]
        for i in range(7):
            if i == 6:
                subData[2][6] = temp
            else:
                subData[2][i] = subData[2][i+1]
    ## Get the rotated data and the 8 target elements in the middle
    targetdict = findTarget(subData)
    return subData,targetdict

# Find the scheme with the smallest length and save it
def findWays(ways):
    LEN = len(ways)
    if LEN == 1:
        return ways[0]
    else:
        Init_len = math.inf
        FianlWays = []
        for i in range(LEN):
            temp = ways[i][0]
            if len(temp) < Init_len: # Determine the minimum length of the scheme
                Init_len = len(temp)
        for i in range(LEN):# Find the scheme with the smallest length
            temp = ways[i][0]
            if len(temp) == Init_len:
                FianlWays.append(ways[i])
    ## Look for the scheme with the same length but the smallest alphabetical order
    LEN = len(FianlWays)
    if LEN==1:
        return FianlWays[0]
    else:
        len2 = len(FianlWays[0][0])
        Init_int = math.inf
        for i in range(LEN):
            temp = FianlWays[i][0]
            res = ''
            for j in range(len2):
                res = res + str(temp[j])
            if int(res) < Init_int: # Find alphabetic minimum
                Init_int = int(res)
        ## Determine the scheme corresponding to the minimum value of alphabetic sorting
        for i in range(LEN):
            temp = FianlWays[i][0]
            res = ''
            for j in range(len2):
                res = res + str(temp[j])
            if int(res) == Init_int: # Find alphabetic minimum
                return FianlWays[i]

## Start DFS processing
class Solutions:
    def DFS(self):
        # Sets the deepest depth of DFS
        self.MaxDeep = 4 # This data is particularly effective and helps to improve the execution speed of the algorithm.
        # Query the elements of the target area
        targetdict = findTarget(subData)
        # Store final results
        self.FinalWays = []
        for candicate_i in range(3):
            ## 1 initially select the initial target elements (the largest number)
            if candicate_i == 0:
                label = targetdict['max'][0]
                label_num = targetdict['max'][1]
            elif candicate_i == 1:
                label = targetdict['mid'][0]
                label_num = targetdict['mid'][1]
            elif candicate_i == 2:
                label = targetdict['min'][0]
                label_num = targetdict['min'][1]
            ## 2 next, is it going to rotate?
            self.ways = []
            for dir_i in range(8):
                step = [dir_i]
                self.dfs(subData,label,label_num,dir_i,step)
            ## 3 find the scheme with the smallest length and save it
            if len(self.ways)>0:# It indicates that a suitable scheme has been found
                # Find the scheme with the smallest length and save it
                Ways = findWays(self.ways)
                self.FinalWays.append(Ways)
                break
        # Process the saved scheme
        if len(self.FinalWays)>0: # It shows that there is a feasible scheme
            # Output according to the output requirements.
            return findWays(self.FinalWays)
        else:
            # It indicates that there is no feasible scheme
            return "No Solution"

    def dfs(self,data,label,label_num,dir,step):
        # Set the rotation and return the rotated matrix and the dictionary of the target area
        new_subData, new_targetdict = Rotation(data, dir)
        new_label = new_targetdict['max'][0]
        new_label_num = new_targetdict['max'][1]
        # What is terminated or not: 1:
        if new_label == label:
            if new_label_num == 8:# The label does not change, and the target area is the same element
                self.ways.append([step,label])# Save the current scheme and label
                return
        else:
            return
        # Termination 2: if the step exceeds the expected depth, an error is reported and returned
        if len(step) > self.MaxDeep:
            return
        ## 2. If the termination conditions are not met, continue to execute
        if new_label == label and new_label_num>=label_num: # It is valid only when the target element remains unchanged and the number does not decrease
            # Proceed to the next dfs cycle
            for dir_i in range(8):
                new_step = []
                new_step.append(dir_i)
                for step_i in step:
                    new_step.append(step_i)
                # Ensure that the order cannot be changed, otherwise the order will be wrong when the final output is made
                new_step.append(dir_i) # Add at tail
                # And remove the data of the head
                new_step.pop(0)
                self.dfs(new_subData,new_label,new_label_num,dir_i,new_step)
        else:
            return
        return

## First, welcome the data and store the data in a 7 * 7 matrix
data = []
while True:
    n = input().strip()
    if len(n) == 1 and int(n)==0:
        break
    # Stored in the matrix
    temp = list(map(int,n.strip().split(' ')))
    data.append(temp)
# print(data)
# Number of case s
N = len(data)
# Set operation flag
action = {0:['A'],1:['B'],2:['C'],3:['D'],4:['E'],5:['F'],6:['G'],7:['H']}

for casei in range(N):
    subData = data[casei]
    # Convert data to matrix
    subData = data2Matrix(subData)
    test = Solutions()
    ans = test.DFS()
    # Print
    res = ''
    for i in ans[0]:
        res = res + action[i][0]
    print(res)
    print(ans[1])


Input:

1 1 1 1 3 2 3 2 3 1 3 2 2 3 1 2 2 2 3 1 2 1 3 3
1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3
0

Output:

AC
2
DDHH
2

Topics: Python Algorithm