Python - 八皇后问题简析。

八皇后问题简介:

    将8个皇后放入8 * 8的棋盘中,任意两个皇后不能在同一条直线或对角线上。(可引申至 n 皇后问题)

    示例 - 目标输出结果:

                    Python - 八皇后问题简析。_第1张图片

Method - 1

暴力随机法,通过无限随机找到一个符合条件的解:(用到random, copy) 找到一个解的效率很高,但找到全部解方面效率低。

# Method1 - 暴力随机
import random
import copy

dimension = 8
total = 0


# Check if the list satisfy the diagonal requirement
# 检查传入 list 是否满足对角线条件
def conflict(i_list):

    list_len = len(i_list)
    plus_list = list()
    minus_list = list()
    for i in range(list_len):
        plus_list.append(i_list[i] + i)     # 存放 y+x 的值 (Comment: 用 abs() 会更简洁)
        minus_list.append(i_list[i] - i)    # 存放 y-x 的值
    for i in range(list_len - 1):           # 如若任何两个 y+x 或 y-x 的值相等,返回冲突
        if plus_list[i] == plus_list[i+1]:
            return True
        if minus_list[i] == minus_list[i+1]:
            return True
    return False                            # 反之不冲突


# Generate a list of 8 numbers randomly
# 随机生成一个包含 1-8 的数列(元素不重复)
def generate():
    global total
    total += 1
    v_list = []
    r_list = []
    for i in range(dimension):
        v_list.append(i+1)
    for i in range(dimension):
        rand_num = random.randint(0, dimension-1-i)
        r_list.append(v_list[rand_num])
        v_list.remove(v_list[rand_num])
    return r_list


# Main part for generate a justified list and display
# 主函数,生成 list 并且画出来
def main():

    q_list = generate()
    display_str = list()
    line = list()
    display = list()
    for i in range(dimension):
        display_str.append('')
        line.append(' ')
    while conflict(q_list):     # 生成合法的 list 其中 index 和 value 分别对应行和 Q 的位置
        print('Loop')
        q_list = generate()

    for i in range(dimension):          # 以下是为了方便展示对于 list 的处理
        display.append(copy.copy(line))
        display[i][q_list[i]-1] = 'Q'
        for j in range(0, dimension*2 + 2, 2):
            display[i].insert(j, '|')
        for c in display[i]:
            display_str[i] += c
    for i in display_str:
        print(i)
    print('Number of counts: ', total)

main()

Method - 2

递归筛选法,通过遍历所有位置查找符合的解:在处理找到全部解的问题时会更快。

# Method 2 - 递归求解
import copy

dimension = 8
total = 0
q_list = list()
start = 0


# 接收一个 list 并返回检查值,作用与Method1中相同
def conflict(i_list):

    list_len = len(i_list)
    plus_list = list()
    minus_list = list()
    for i in range(list_len):
        plus_list.append(i_list[i] + i)     # 存放 y+x 的值
        minus_list.append(i_list[i] - i)    # 存放 y-x 的值
    for i in range(list_len - 1):           # 如若任何两个元素 y 或 y+x 或 y-x 的值相等,返回冲突
        if plus_list[i] == plus_list[i+1]:
            return True
        if minus_list[i] == minus_list[i+1]:
            return True
    for i in q_list:
        if i_list.count(i) > 1:
            return True
    return False                            # 反之不冲突


# 顺序寻找第一个符合要求的Q_list
def queens(row, pos):                       # row 是判断的行,pos 是该行开始判断的点
    global total, q_list, start
    total += 1
    if row == dimension:                    # 如果满 8 行输出得到的 list
        return q_list
    else:                                   # 未满 8 行,判断 list 是否合法
        for i in range(pos, dimension):     # 从该行检测位置一直检测到 8 如果有合法的值,检测下一行
            q_list.append(i)
            if not conflict(q_list):        # 合法
                print('No conflict. Processing to next line. Current list: ', q_list)
                return queens(row + 1, 0)   # 检测下一行
            else:                           # 不合法,测试下一个位置
                print('Conflict occurs. Trying next pos. Current list: ', q_list)
                q_list = q_list[:len(q_list)-1]
                continue

        # 当前行没有合法值,退回前一行或者前两行
        start = q_list[-1]
        print('No proper value found. Back to check last row.', q_list, ' Start: ', start)
        if start < 7:                       # 如果前一行的已检测到的合法值 < 7, 测试该行下一个位置
            start += 1
            q_list = q_list[:len(q_list)-1]
            return queens(row - 1, start)

        else:                               # 如何前一行的已检测值 = 7,再退回一行,检测该行的下一个位置
            start = q_list[-2]
            q_list = q_list[:len(q_list)-2]
            return queens(row - 2, start + 1)


def main():     # 展示找到的 Q_list
    r_list = queens(0, 0)
    display_str = list()
    line = list()
    display = list()
    for i in range(dimension):
        display_str.append('')
        line.append(' ')
    print(r_list)
    for i in range(dimension):          # 以下是为了方便展示对于 list 的处理
        display.append(copy.copy(line))
        display[i][r_list[i]] = 'Q'
        for j in range(0, dimension*2 + 2, 2):
            display[i].insert(j, '|')
        for c in display[i]:
            display_str[i] += c
    for i in display_str:
        print(i)
    print('Number of counts: ', total)


main()


你可能感兴趣的:(Algorithm,Learning)