Обобщить построение греко-римской матрицы - Python - PullRequest
0 голосов
/ 30 апреля 2018

Я написал программу на Python, в которой в качестве входных данных используется матрица, в которой каждый элемент появляется в каждой строке и столбце по одному разу. Элементы являются только положительными целыми числами.

например.

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

Тогда я найду все возможные обходы. Они определены как таковые:

  • выбрать элемент из первого столбца
  • перейти к следующему столбцу и
  • выберите элемент, который не находится в той же строке, что и предыдущие элементы в обходе, и этот элемент не совпадает со значением предыдущих элементов в обходе.

, например * * 1016

0,*,*,*
*,*,*,2
*,3,*,*
*,*,1,*

Я построил код, который находит обходы для матриц 4x4, но у меня возникают проблемы с его обобщением для матриц NxN. Мой код следует ниже. Не ищите решения, любой совет будет полезен.

import sys       # Import to input arguments from cmd.
import pprint    # Import for a cool print of the graph
import itertools # Import to find all crossings' combinations

# Input of arguments
input_filename = sys.argv[1]

# Create an empty graph
g = {} 
# Initialize variable for the list count
i = 0 

# Opens the file to make the transfer into a matrix
with open(input_filename) as graph_input:
    for line in graph_input:
        # Split line into four elements.
        g[i] = [int(x) for x in line.split(',')]
        i += 1

# Initialize variable
var = 0
# Lists for the crossings, plus rows and cols of to use for archiving purposes
f = {}
r = {}
c = {}
l = 0

# Finds the all the crossings
if len(g) == 4:
    for x in range (len(g)): 
        for y in range (len(g)):
            # When we are in the first column
            if y == 0:
                # Creates the maximum number of lists that don't include the first line
                max_num = len(g) -1
                for z in range (max_num):
                    f[l] = [g[x][y]]
                    r[l] = [x]
                    c[l] = [y]
                    l += 1
            # When on other columns
            if y != 0:
                for z in range(len(g)):
                    # Initializes a crossing archive
                    used = [-1]
                    for item in f:
                        # Checks if the element should go in that crossing
                        if f[item][0] == g[x][0]:
                            if g[z][y] not in f[item] and z not in r[item] and y not in c[item] and g[z][y] not in used:
                                # Appends the element and the archive  
                                f[item].append(g[z][y])
                                used.append(g[z][y])
                                r[item].append(z)
                                c[item].append(y)

# Removes unused lists 
for x in range (len(f)):
    if len(f[x]) != len(g):
        f.pop(x)

#Transfers the value from a dictionary to a list
f_final = f.values()

# Finds all the combinations from the existing crossings
list_comb = list(itertools.combinations(f_final, i))

# Initialize variables
x = 0
w = len(list_comb)
v = len(list_comb[0][0])

# Excludes from the combinations all invalid crossings
while x < w:
    # Initialize y
    y = 1
    while y < v:
        # Initialize z
        z = 0
        while z < v:
            # Check if the crossings have the same element in the same position
            if list_comb[x][y][z] == list_comb[x][y-1][z]:
                # Removes the combination from the pool
                list_comb.pop(x)
                # Adjust loop variables
                x -= 1
                w -= 1
                y = v
                z = v
            z += 1
        y += 1
    x += 1  

# Inputs the first valid solution as the one to create the orthogonal latin square
final_list = list_comb[0]

# Initializes the orthogonal latin square matrix
orthogonal = [[v for x in range(v)] for y in range(v)]

# Parses through the latin square and the chosen solution
# and creates the orthogonal latin square
for x in range (v):
    for y in range (v):
        for z in range (v):
            if final_list[x][y] == g[z][y]:
                orthogonal[z][y] = int(final_list[x][0])
                break

# Initializes the orthogonal latin square matrix
gr_la = [[v for x in range(v)] for y in range(v)]

# Creates the greek-latin square
for x in range (v):
    for y in range (v):
        coords = tuple([g[x][y],orthogonal[x][y]])
        gr_la[x][y] = coords

pprint.pprint(gr_la)

Допустимые обходы для матрицы 4x4, приведенной выше:

[[0123],[0312],[3210],[3021],[1203],[1032],[2130],[2301]]
...