Here comes the reference answer to the python exercise question (super code). Have a look?

A few basic python grammar topics have been posted earlier, which are mainly used to help test the mastery of basic knowledge. If you have carefully read or done them, I believe you should have a certain understanding of your mastery of knowledge. Next, you can relearn the part that is not very clear.

python basic syntax is OK? Do some tests

python basic syntax is OK? Do some tests (2)

python solution is OK? Do some tests (3)

Among the above three articles, the first and second articles are relatively simple. The content of the third article is indeed difficult if you have not specially studied the content related to data structure and algorithm. This is the opposite. Let's put the reference answers of the most difficult article first, and put the first and second articles in the next issue.

If you haven't read the third article, I suggest you think about it yourself first and try it according to your existing knowledge. Efficient learning or learning effect learning must produce a lot of effective thinking per unit time - that is, you have tried hard and tried various methods, but these thoughts are very helpful. You know your puzzles and problems to be solved; When you see the reference answer, it is completely different from those who have not thought. When these contents are successfully solved, your brain should make subtle changes in the game and make breakthroughs in technology.

Now officially enter the topic.

In order to make you better understand the following contents, let's talk about some larger concepts first.

Cycle of violence (exhaustive): most computer problems can be solved by exhaustive without considering time.

For example, we can find out all the schemes through exhaustive methods, and then find the one with the least quantity.

The same is true for Sudoku. There are four possibilities for each position. You can list all methods, and then judge the coincidence.

Similarly, the maze problem is the same.

The cycle of violence mentioned above is simple, but there are also some problems to face:

  1. How to ensure that all the information can be listed without omission?
    1. For example, how many non repeated 3 digits can be combined from 3, 4, 5, 6 and 4 numbers?
    2. 24 point game, random four numbers, 1, 3, 6, 9, plus, minus, multiplication and division (+ - * /), parentheses, how many situations can be combined?
  2. How to judge whether the current situation is inconsistent? Different problems lead to different difficulties. It's easy to judge the change. Maze and Sudoku are a little more troublesome.
  3. There is a large amount of data. It has been a long time without results. How can we speed up some speed?
  4. ......

To solve some of the above problems, we need to have some strategies, such as how to ensure that the poor cite all the cases, and the permutation and combination in mathematics is very popular.

There are many ways to realize permutation and combination. For example, I have used multiple loops before, and of course I can also use recursion.

Full Permutation and combination implementation method

This method ensures that there is no leakage. The tree structure and many decision trees are similar.

Question 2 specific analysis.

Problem 3: to reduce the data scale is to use recursion to calculate Fibonacci series. After 40 items are calculated, it is not increased once. The time is double. The computer card is stuck for a long time. The reason is repeated calculation. You can save the calculated values through a list and reduce repeated calculation, which will significantly improve the speed.

For example, if you find the target number in a range and judge it one by one from beginning to end, it must be slow. Two point search can cut half at a time. How large the range is, it becomes smaller after several times.

1. Find the smallest tuple value in the following list, and the maximum value is the same.

[(0, 1, 2), (3, 4, 5), (6, 7, 8), (9, 10, 11), (12, 13, 14), (15, 16, 17), (18, 19, 20), (21, 22, 23), (24, 25, 26)]

result:

Minimum:(0, 1, 2)
Maximum:(24, 25, 26)

2. Find the most frequent element in the following list and print the number.

l = [1,3,4,5,6,1,3,4,5,1,9,1,1,1]

result:

1 Up to 6 times.

Reference for questions 1 and 2: python mosaic pixel map , which gives the solution.

3. Change problem

Given the types of change that can be found and the total amount of change to be found, find the scheme of the least amount of change.

For example, change 6 yuan,

Scheme 1: 4 1;

Scheme 2: 3,3;

Scheme 3: 3,1,1,1;

Scheme 4: 1,1,1,1,1,1;

Obviously, scheme 2 has the least number, only 2.

values = [1, 3, 4]  # Coin face value
total = 6  # I need change

result:

[3,3]

Refer to answer 1 - local optimal solution:

# Target number of change
total = 6
# Types of banknotes
values = [4, 3, 1]
# result
number = [0,0,0]


# Cycle, starting from the maximum face value
for i in range(3):
    # Rounding to calculate the maximum number of sheets that can be found for the current face value
    number[i] = total // values[i]
    # Take the balance and calculate the amount of money left after the change of the current face value
    total = total % values[i]
    
for i in range(3):
    print(values[i],'The number of sheets of yuan is:',number[i],'Zhang')

Reference answer 2 - global optimal solution (dynamic programming):

I'm too lazy to write. I found a number on the Internet and changed it. I feel it's still very clear

def rec_mc(coin_value_list, change, know_results):
    min_coins = change
    if change in coin_value_list:
        know_results[change] = 1
        return 1
    elif know_results[change] > 0:
        return know_results[change]
    else:
        for i in [c for c in coin_value_list if c <= change]:
            num_coins = 1 + rec_mc(coin_value_list, change-i, know_results)
            if num_coins < min_coins:
                min_coins = num_coins
                know_results[change] = min_coins
    return min_coins
 
print("===========Recursive implementation========================")
print(rec_mc([1, 3, 4], 6, [0]*7))
 
def dp_make_change(coin_value_list, change, min_coins, coins_used):
    for cents in range(change+1):
        coin_count = cents
        new_coin = 1
        for j in [c for c in coin_value_list if c <= cents]:
            if min_coins[cents-j] + 1 < coin_count:
                coin_count = min_coins[cents-j]+1
                new_coin = j
        min_coins[cents] = coin_count
        coins_used[cents] = new_coin
    return min_coins[change]
 
def print_coins(coins_used, change):
    coin = change
    while coin > 0:
        this_coin = coins_used[coin]
        print(this_coin)
        coin = coin - this_coin
 
a_mnt = 6
c_list = [1, 3, 4]
c_used = [0] * (a_mnt+1)
c_count = [0] * (a_mnt+1)
print("===========Dynamic programming implementation========================")
print('Making change for ', a_mnt, 'requires')
print(dp_make_change(c_list, a_mnt, c_count, c_used), 'coins')
print("They are: ")
print_coins(c_used, a_mnt)
print("The used list is as follows: ")
print(c_used)

4. Sudoku 4

Using the program to automatically complete 4 * 4 Sudoku

[[0, 1, 0, 0], 
 [0, 0, 0, 2], 
 [3, 0, 0, 0],
 [0, 0, 4, 0]]

result:

answer:

# Print board
def print_board(board):
    for row in board:
        print(row)

def check_board(num,row,col):
    # Check the row and judge each grid of the row
    for i in range(cols):
        # If the number to be filled already exists
        if board[row][i] == num:
            return False
    # Check the column and judge each grid of the column
    for i in range(rows):
        # If the number to be filled already exists
        if board[i][col] == num:
            return False
    return True

def backtrack(board, index):
    if index >= 16:
        print("----programme----")
        print_board(board)
        print("------------")   
    else:
        for num in range(1, len(board)+1):
            row = index//len(board)
            col = index%len(board[0])
            if board[row][col]==0:
                # Judge whether this number can be filled in
                if not check_board(num, row, col):
                    continue
                # Select a number
                board[row][col] = num
                backtrack(board,index+1)
                # Number of unselected
                board[row][col] = 0
            else:
                index = index +1
rows = 4
cols = 4
board = [[0 for i in range(rows)] for j in range(cols)]
board[0][1] = 1
board[1][3] = 2
board[2][0] = 3
board[3][2] = 4
index = 0
backtrack(board,index)

Unpackaged visual Sudoku version:

from PIL import Image, ImageDraw
import matplotlib.pyplot as plt
#Title Setting Chinese
plt.rc("font", family='MicroSoft YaHei', weight='bold')
plt.ion()

# Print board
def print_board(board):
    for row in board:
        print(row)


def show_board(board, x, y, num):
    img = Image.new("RGB", (100, 100), "white")
    draw = ImageDraw.Draw(img)
    for row in range(4):
        for col in range(4):
            pos = (0+30*col, 0+row*30)
            draw.text(pos, str(board[row][col]), fill=(0, 0, 255))
    draw.text((0+30*y, 0+x*30), str(num), fill=(255, 0, 255))
    return img

def check_board(num, row, col):
    # Check the row and judge each grid of the row
    for i in range(cols):
        # If the number to be filled already exists
        if board[row][i] == num:
            return False
    # Check the column and judge each grid of the column
    for i in range(rows):
        # If the number to be filled already exists
        if board[i][col] == num:
            return False
    return True


def backtrack(board, index):
    if index >= 16:
        print("----programme----")
        print_board(board)
        print("------------")
        img = show_board(board, 3, 3, board[3][3])
        plt.title("Compliant scheme")   # title
        plt.imshow(img)
        plt.pause(5)  # Pause for 1 second
    else:
        for num in range(1, 4+1):
            row = index//4
            col = index % 4
            if board[row][col] == 0:
                # Judge whether this number can be filled in
                if not check_board(num, row, col):
                    continue
                # Select a number
                board[row][col] = num
                plt.cla()  # Clear the screen first
                img = show_board(board, row, col, num)
                plt.title("Fill in a number")   # title
                plt.imshow(img)
                plt.pause(1)  # Pause for 1 second
                backtrack(board, index+1)
                # Number of unselected
                board[row][col] = 0
                plt.cla()  # Clear the screen first
                img = show_board(board, row, col, num)
                plt.title("Cancel a number")   # title
                plt.imshow(img)
                plt.pause(1)  # Pause for 1 second
            else:
                index = index + 1


rows = 4
cols = 4
board = [[0 for i in range(rows)] for j in range(cols)]
board[0][1] = 1
board[1][3] = 2
board[2][0] = 3
board[3][2] = 4
# plt.pause(5)
img = show_board(board, 3, 3, board[3][3])
plt.title("4X4 Sudoku game")   # title
plt.imshow(img)
plt.pause(5)
plt.title("start")
plt.pause(2)
index = 0
backtrack(board, index)
plt.pause(2)  # Pause for 1 second
plt.ioff()
plt.show()

5. Sudoku 9

Increase the difficulty and use the program to automatically complete 9 * 9 Sudoku.

[[2, 0, 0, 0, 0, 0, 0, 0, 0],
 [0, 0, 3, 6, 0, 0, 0, 0, 0],
 [0, 7, 0, 0, 9, 0, 2, 0, 0],
 [0, 5, 0, 0, 0, 7, 0, 0, 0],
 [0, 0, 0, 0, 4, 5, 7, 0, 0],
 [0, 0, 0, 1, 0, 0, 0, 3, 0],
 [0, 0, 1, 0, 0, 0, 0, 6, 8],
 [0, 0, 8, 5, 0, 0, 0, 1, 0],
 [0, 9, 0, 0, 0, 0, 4, 0, 0]]

Results: there are many answers, and only some are listed below.

answer:

# Print board
def print_board(board):
    for row in board:
        print(row)

def check_board(num,row,col):
    # Check whether there are duplicate numbers in the row and column
    for i in range(9):
        if board[row][i] == num or board[i][col] == num:
            return False

    # Judge whether there is repetition in xiaojiugong
    sub_row = row // 3
    sub_col = col // 3
    for i in range(3): 
        for j in range(3):
            if board[sub_row * 3 + i][sub_col * 3 + j] == num:
                return False
    return True

def backtrack(board, index):
    # print(index)
    if index >= 81:
        print("-----------programme-----------")
        print_board(board)
        print("--------------------------")   
    else:
        for num in range(1, 9+1):
            row = index//9
            col = index%9
            if board[row][col]==0:
                # Judge whether this number can be filled in
                if not check_board(num, row, col):
                    continue
                # Select a number
                board[row][col] = num
                # Continue to select the next number
                backtrack(board,index+1)
                # Number of unselected
                board[row][col] = 0
            else:
                # backtrack(board,index+1)
                index = index + 1

board = [[2, 0, 0, 0, 0, 0, 0, 0, 0],
         [0, 0, 3, 6, 0, 0, 0, 0, 0],
         [0, 7, 0, 0, 9, 0, 2, 0, 0],
         [0, 5, 0, 0, 0, 7, 0, 0, 0],
         [0, 0, 0, 0, 4, 5, 7, 0, 0],
         [0, 0, 0, 1, 0, 0, 0, 3, 0],
         [0, 0, 1, 0, 0, 0, 0, 6, 8],
         [0, 0, 8, 5, 0, 0, 0, 1, 0],
         [0, 9, 0, 0, 0, 0, 4, 0, 0]]

index = 0
backtrack(board,index)

Unpackaged visual Sudoku version:

from PIL import Image,ImageDraw
import matplotlib.pyplot as plt
#Title Setting Chinese
plt.rc("font", family='MicroSoft YaHei', weight='bold')
plt.ion()

# Print board
def print_board(board):
    for row in board:
        print(row)


def show_board(board,x,y,num):
    img = Image.new("RGB", (250, 250), "white")
    draw = ImageDraw.Draw(img)
    for row in range(9):
        for col in range(9):
            pos = (0+30*col, 0+row*30)
            draw.text(pos, str(board[row][col]), fill=(0, 0, 255))
    draw.text((0+30*y, 0+x*30), str(num), fill=(255, 0, 255))
    return img


def check_board(num, row, col):
    # Check whether there are duplicate numbers in the row and column
    for i in range(9):
        if board[row][i] == num or board[i][col] == num:
            return False

    # Judge whether there is repetition in xiaojiugong
    sub_row = row // 3
    sub_col = col // 3
    for i in range(3):
        for j in range(3):
            if board[sub_row * 3 + i][sub_col * 3 + j] == num:
                return False
    return True


def backtrack(board, index):
    global count
    # print(index)
    if index >= 81:
        count = count + 1
        img = show_board(board, 8, 8, board[8][8])
        plt.title("The first{}Suspension of 1 eligible scheme s".format(count))   # title
        plt.imshow(img)
        plt.pause(1)  # Pause for 1 second
        plt.title("Next plan")   # title
        plt.pause(1)  # Pause for 1 second
        print("-----------------------")
        print_board(board)
    else:
        for num in range(1, 9+1):
            row = index//9
            col = index % 9
            if board[row][col] == 0:
                # Judge whether this number can be filled in
                if not check_board(num, row, col):
                    continue
                # Select a number
                board[row][col] = num
                plt.cla()  # Clear the screen first
                img = show_board(board,row,col,num)
                plt.title("Fill in a number")   # title
                plt.imshow(img)
                plt.pause(0.1)  # Pause for 1 second
                # Continue to select the next number
                backtrack(board, index+1)
                # Number of unselected
                board[row][col] = 0
                plt.cla()  # Clear the screen first
                img = show_board(board,row,col,num)
                plt.title("Cancel a number")   # title
                plt.imshow(img)
                plt.pause(0.1)  # Pause for 1 second
            else:
                # backtrack(board,index+1)
                index = index + 1
                plt.cla()  # Clear the screen first
board = [[2, 0, 0, 0, 0, 0, 0, 0, 0],
         [0, 0, 3, 6, 0, 0, 0, 0, 0],
         [0, 7, 0, 0, 9, 0, 2, 0, 0],
         [0, 5, 0, 0, 0, 7, 0, 0, 0],
         [0, 0, 0, 0, 4, 5, 7, 0, 0],
         [0, 0, 0, 1, 0, 0, 0, 3, 0],
         [0, 0, 1, 0, 0, 0, 0, 6, 8],
         [0, 0, 8, 5, 0, 0, 0, 1, 0],
         [0, 9, 0, 0, 0, 0, 4, 0, 0]]

img = show_board(board, 8, 8, board[8][8])
plt.title("9X9 Sudoku game")   # title
plt.imshow(img)
plt.pause(2)
plt.title("start")
plt.pause(2)
index = 0
global count
count = 0
backtrack(board, index)
# plt.ioff()
plt.show()

6. Maze problem

A maze with a size of 5 * 6 is given, which is composed of channel (0) and wall (1), in which the upper left corner of the channel represents the starting point and the lower right corner of the channel represents the end point. Find the maze path.

maze = [[0, 1, 0, 0, 0],
        [0, 0, 0, 1, 0],
        [0, 1, 0, 1, 0],
        [1, 1, 1, 0, 0],
        [0, 1, 0, 0, 1],
        [0, 1, 0, 0, 0]]

result:

[[0, 0], [1, 0], [1, 1], [1, 2], [0, 2], [0, 3], [0, 4],
 [1, 4], [2, 4], [3, 4], [3, 3], [4, 3], [5, 3], [5, 4]]

Answer 1:

# Shortest distance shortest path
maze =[[0, 1, 0, 0, 0],
       [0, 1, 0, 1, 0],
       [0, 0, 0, 0, 0],
       [0, 1, 1, 1, 0],
       [0, 0, 0, 1, 0]]
n,m = len(maze),len(maze[0])
start = [0, 0]
end = [4, 4]
# List of data to be found
search_queue = []  # List simulation queue
# Add start point
search_queue.append(start)
visted = []  # Record visited points
visted.append(start)

def find_next_point(point):
    global search_queue,visted,n,m
    # px and py arrays are used to realize the moving order of bottom left and top right
    px = [-1, 0, 1, 0]   
    py = [0, -1, 0, 1]
    # Move up, down, left and right
    for i in range(4):
        next_x = point[0] + px[i]
        next_y = point[1] + py[i]
        # How to add the next point to the queue to be searched and the access queue to meet the requirements
        if (0 <= next_x < n and 0 <= next_y < m and maze[next_x][next_y] == 0 and [next_x,next_y] not in visted):
            search_queue.append([next_x,next_y])
            visted.append([next_x,next_y])
            return True     
    return False
    

def dfs():
    global search_queue,visted
    print(search_queue)
    while search_queue[-1] != end:
        # Get the last point of the queue and judge whether to reach the big end point
        point = search_queue[-1]
        # If there is a next point, continue
        if find_next_point(point):
            continue
        # Otherwise, delete the point you just added
        else:
            print("delete",search_queue.pop())
    print(search_queue)

dfs()

Answer 2:

The above is difficult to understand. You can see the following. I found a simple change on the Internet. It is easier to understand, but there are many codes

def up(point):
    # You have reached the top of the array. You can't go up
    if point[0] == 0:
        return False
    else:
        new_point = [point[0] - 1, point[1]]
        # The road we have traveled is no longer gone
        if new_point in visted:
            return False
        # Don't go against the wall
        elif maze[new_point[0]][new_point[1]] == 1:
            return False
        else:
            search_queue.append(new_point)
            visted.append(new_point)
            return True
 
 
def down(point):
    # When you meet the bottom of the maze, you can't go further
    if point[0] == len(maze) - 1:  # The number of two-dimensional array rows with 6 rows and 5 columns is calculated from 0, so it is 6-1 = 5 rows
        return False
    else:
        new_point = [point[0] + 1, point[1]]
        # The road we have traveled is no longer gone
        if new_point in visted:
            return False
        # Don't go against the wall
        elif maze[new_point[0]][new_point[1]] == 1:
            return False
        else:
            visted.append(new_point)
            search_queue.append(new_point)
            return True
 
 
def left(point):
    # You can't continue to go left when you meet the leftmost part of the maze
    if point[1] == 0:
        return False
    else:
        new_point = [point[0], point[1] - 1]
        # The road we have traveled is no longer gone
        if new_point in visted:
            return False
        # Don't go against the wall
        elif maze[new_point[0]][new_point[1]] == 1:
            return False
        else:
            visted.append(new_point)
            search_queue.append(new_point)
            return True
 
 
def right(point):
    # You cannot continue to move to the right when you encounter the rightmost side of the maze
    if point[1] == len(maze[0]) - 1:  # The number of two-dimensional array columns with 6 rows and 5 columns is calculated from 0, so it is 5-1 = 4 rows
        return False
    else:
        new_point = [point[0], point[1] + 1]
        # The road we have traveled is no longer gone
        if new_point in visted:
            return False
        # Don't go against the wall
        elif maze[new_point[0]][new_point[1]] == 1:
            return False
        else:
            visted.append(new_point)
            search_queue.append(new_point)
            return True
 

maze = [[0, 1, 0, 0, 0],
        [0, 0, 0, 1, 0],
        [0, 1, 0, 1, 0],
        [1, 1, 1, 0, 0],
        [0, 1, 0, 0, 1],
        [0, 1, 0, 0, 0]]
start = [0, 0]
end = [5, 4]

search_queue = []
visted = []
search_queue.append(start)
visted.append(start)

print("start: %s --> end: %s\n" % (start, end))
while search_queue[-1] != end:
    now = search_queue[-1]
    if up(now) or down(now) or left(now) or right(now):
        continue
    print("delete",search_queue.pop())
 
print("final path: ", search_queue)

7. Maze problem 2 - shortest path.

Given a maze with a size of 5 * 5, it is composed of channel (0) and wall (1), in which the upper left corner of the channel represents the starting point and the lower right corner of the channel represents the end point, so as to find the shortest path of the maze.

maze = [[0, 1, 0, 0, 0,],
        [0, 1, 0, 1, 0,],
        [0, 0, 0, 0, 0,],
        [0, 1, 1, 1, 0,],
        [0, 0, 0, 1, 0,]]

There are two schemes, but scheme 2 is the shortest path.

answer:

# Shortest distance shortest path
maze =[[0, 1, 0, 0, 0],
       [0, 1, 0, 1, 0],
       [0, 0, 0, 0, 0],
       [0, 1, 1, 1, 0],
       [0, 0, 0, 1, 0]]
n,m = len(maze),len(maze[0])
start = [0, 0]
end = [4, 4]

# Define the Breadth First Search algorithm
def bfs(maze,n,m):
    # List of data to be found
    search_queue = []  # List simulation queue
    # Add start point
    search_queue.append(start)
    visted = []  # Record visited points
    visted.append(start)
    # Record parent node
    parent = {f"{start[0]}{start[1]}":None}
    px = [-1, 0, 1, 0]   # px and py arrays are used to realize the moving order of bottom left and top right
    py = [0, -1, 0, 1]
    # Exit the loop until the lookup queue is empty
    while search_queue:
        # Take out the first point in the queue (search started recently)
        point = search_queue.pop(0)
        # Get all nearest points
        points = []
        for i in range(4):
            next_x = point[0] + px[i]
            next_y = point[1] + py[i]
            if (0 <= next_x < n and 0 <= next_y < m and maze[next_x][next_y] == 0):
                points.append([next_x,next_y])
        for i in points:
            # If i have not been visited
            if i not in visted:
                # Add I (nearest point) to the search queue
                search_queue.append(i)
                # Mark i as accessed
                visted.append(i)
                # Record the parent node of each point
                parent[f"{i[0]}{i[1]}"] = point
    return visted,parent

visted,parent = bfs(maze,n,m)

route_list = []
if end in visted:
    print(f"Existence from{start}reach{ end}Route")
    v = end # Currently accessed point
    # Until the start position None exits
    while v !=None:
        route_list.append(v)
        v=parent[f"{v[0]}{v[1]}"]
else:
    print(f"Does not exist from{start}reach{ end}Route")
route_list.reverse()
print(route_list)

How to see the above methods is difficult. You can look at the concepts of DFS and BFS, backtracking, recursion and so on. You can also take a look at what I wrote before. I have time to update it later. What I wrote before is not very good. I can make do with it.

Recursive algorithm (I)

Recursive algorithm (Part 2)

Full Permutation and combination implementation method

Thoughts on learning algorithms (end of full text)

Added by dbair on Thu, 30 Dec 2021 22:03:16 +0200