Как сбалансировать заполнение int в матрицу symri c - PullRequest
1 голос
/ 09 июля 2020

Допустим, у меня есть матрица A, это симметрия c. То есть A(i,j)=A(j,i)

Значение A(i,j) может быть i или j.

Как я могу заполнить значение в матрице A, чтобы убедиться, что время существования каждого значение как можно ближе? (или как можно более сбалансированно)? Есть ли какой-либо алгоритм, который может справиться с этим?

Пример A:

A = 1 1 1 1
    1 2 2 2
    1 2 3 3
    1 2 3 4 
exist times of 1 is 7
exist times of 2 is 5
exist times of 3 is 3
exist times of 4 is 1

Пример B:

A = 1 2 1 1
    2 2 3 2
    1 3 3 4
    1 2 4 4 
exist times of 1 is 5
exist times of 2 is 4
exist times of 3 is 3
exist times of 4 is 3

В примере B значения (5,4,3 , 3), они ближе, чем пример A (7,5,3,1)

Я с нетерпением жду решения для матрицы nxn.

Extend

Если матрица разреженная, то есть некоторые элементы не могут быть заполнены в матрице. Какой алгоритм можно использовать для решения этой проблемы?

Спасибо за ваше время.

Ответы [ 3 ]

1 голос
/ 09 июля 2020

Чтобы получить наилучший результат, необходимо соблюдать особую схему. Для каждого столбца (строки 1) начните заполнять матрицу по диагонали значениями 1, 2, ..., n, фиксируя соответствующий слот симметрии c. В итоге вы получите наилучший результат.

#include <iostream>
using namespace std;

int main(){
    int n = 4;  //size of matrix
    
    int values[n];      for(int i = 0; i < n; i++) values[i] = 0;
    int matrix[n][n];   for(int i = 0; i < n; i++) for(int j = 0; j < n; j++) matrix[i][j] = -1;
    
    for(int c = 0; c < n; c++){
        int i = 0, j = c;
        for(int x = 0; x < n; x++){
            if(matrix[i][j] != -1) {
                break;
            }
            matrix[i][j] = matrix[j][i] = x;
            i = (i + 1) % n;
            j = (j + 1) % n;
        }
    }
    
    for(int i = 0; i < n; i++){
        for(int j = 0; j < n; j++){
            cout<<matrix[i][j] + 1<<" ";
            values[matrix[i][j]]++;
        }
        cout<<endl;
    }
    cout<<endl;
    
    for (int i = 0; i < n; i++) {
        cout<<(i + 1)<<" appears "<<values[i]<<" times"<<endl;
    }

    return 0;
}

ВЫХОД

1 1 1 4 
1 2 2 2 
1 2 3 3 
4 2 3 4 

1 appears 5 times
2 appears 5 times
3 appears 3 times
4 appears 3 times

Вы можете протестировать здесь .

Сложность составляет O (n²), так как вы должны заполнить всю матрицу.

Когда n нечетное, решение всегда n вхождений для каждого числа, но когда n чёт, это невозможно.

1 голос
/ 09 июля 2020

Нашел одно решение, но без реального алгоритма ...

1 2 3 1 1
2 2 3 4 2
3 3 3 4 5
1 4 4 4 5
1 2 5 5 5

В основном: 25/5 = 5, искал как заполнить 5 из каждого 1-5. для 5 - перевернутая L из угла, затем вверх и оставил одно место на 4 секунды, и за 3сек. получил "креатив" для двоек и единиц ... Думаю, это своего рода алгоритм ...

0 голосов
/ 09 июля 2020

Вот решение, написанное на python на основе взвешенного двустороннего сопоставления (или изоморфной c задачи потока минимальной стоимости.)

#!/usr/bin/python

"""
filename: mcf_matrix_assign.py
purpose:  demonstrate the use of weighted bipartite matching (isomorphic to MCF
          with a suitable transform) to solve a matrix assignment problem with
          certain conditions and optimization goals.
"""

import networkx as nx

N = 5
K = N # ensure K is large enough to satisfy flow, N <= K <= N*N
      # setting K larger simply means a longer runtime 

G = nx.DiGraph()
total_demand = 0

for i in range(N*N):
    # assert a row-major linear indexing of the matrix
    row, col = i / N, i % N
    if row >= col:
        continue # symmetry fix certain values
    total_demand += 1
    G.add_node('s'+str(i),demand=-1);
    G.add_edge('s'+str(i), 'v'+str(row), weight = 0, capacity = 1)
    G.add_edge('s'+str(i), 'v'+str(col), weight = 0, capacity = 1)

G.add_node('sink', demand = total_demand)

# attach each 'value' to the sink with incrementally larger weight
for i in range(N):
    for j in range(K):
        dummy_node = 'v'+str(i)+'w'+str(j)
        G.add_edge('v'+str(i), dummy_node, weight = j, capacity = 1)
        G.add_edge(dummy_node, 'sink', weight = 0, capacity = 1)

flow_dict = nx.min_cost_flow(G)

# decode the solution to get the matrix assignment reported by the MCF (or
# equivalently weighted bipartite matching)
solution = [ -1 for i in range(N*N) ]
for i in range(N*N):
    # assert a row-major linear indexing of the matrix
    row, col = i / N, i % N
    if row == col:
        solution[i] = row
        continue # symmetry fix certain values
    if row > col:
        solution[i] = solution[col*N+row]
        continue # symmetry fix certain values
    adjacency = flow_dict['s'+str(i)]
    solution[i] = row if adjacency['v'+str(row)] == 1 else col;


# print the solution
for row in range(N):
    print ''.join(['-' for _ in range(4*N+1)])
    print '|',
    for col in range(N):
        print str(solution[row*N+col]+1) + ' |',
    print '\n',
print ''.join(['-' for _ in range(4*N+1)])

print 'Histogram summary:'
counts = [ (i+1, sum([ 0 if s != i else 1 for s in solution ])) for i in range(N) ]
for value, count in counts:
    print ' Value ', value, " appears ", count, " times."

Это дает решение:

---------------------
| 1 | 1 | 3 | 1 | 5 | 
---------------------
| 1 | 2 | 2 | 4 | 2 | 
---------------------
| 3 | 2 | 3 | 4 | 3 | 
---------------------
| 1 | 4 | 4 | 4 | 5 | 
---------------------
| 5 | 2 | 3 | 5 | 5 | 
---------------------
Histogram summary:
 Value  1  appears  5  times.
 Value  2  appears  5  times.
 Value  3  appears  5  times.
 Value  4  appears  5  times.
 Value  5  appears  5  times.

И вот решение, когда N=4 в скрипте.

-----------------
| 1 | 2 | 1 | 4 | 
-----------------
| 2 | 2 | 3 | 4 | 
-----------------
| 1 | 3 | 3 | 3 | 
-----------------
| 4 | 4 | 3 | 4 | 
-----------------
Histogram summary:
 Value  1  appears  3  times.
 Value  2  appears  3  times.
 Value  3  appears  5  times.
 Value  4  appears  5  times.

Довольно легко доказать, что это всегда найдет оптимальный ответ за полиномиальное время.

Объяснение

Вероятно, проще всего объяснить происходящее, описав построение графа для небольшого случая. Для этого обсуждения исправьте N=3.

В этом случае у нас есть назначение матрицы с переменными

X s0 s1
X X  s2
X X  X

, где X обозначает фиксированное значение, а sk обозначает k -й слот в массиве для заполнения.

В этом случае у нас также есть 3 доступных назначения значений [1,2,3] для каждого из слотов sk. (Здесь легко внести изменения в «разрешенные» значения для любых sk.)

Если мы построим двудольный граф между слотами sk и присвоениями значений v1,v2,v3 в Таким образом, ребра емкости 1 и нулевого веса используются для соединения sk с каждым допустимым назначением vi, мы можем легко решить эту проблему с помощью MCF.

Для иллюстрации соответствующий график для N=3 показано ниже: График, используемый в MCF для случая N = 3.

После вычисления потока минимальной стоимости мы можем декодировать назначение, проверив, какие ребра используются в решении.

Примечание по производительности

networkx было используется здесь в python исключительно для удобства, он ни в коем случае не эффективен в любом смысле этого слова. Качество реализации алгоритма MCF в networkx довольно низкое, и я бы не рекомендовал пытаться его масштабировать.

Для серьезных приложений я бы вместо этого рекомендовал лимонную библиотеку MCF (в частности, алгоритм масштабирования затрат является конкурентоспособным) или вы можете использовать реализацию Эндрю Голдберга масштабирования затрат (которую трудно найти, но она существует) и, вероятно, также довольно эффективна.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...