Posiziona gli elementi X in matrici N senza ripetere la colonna e la riga

1

Ho N matrici ( n × m ) e oggetti da inserire in ciascuna ( n · m ). Gli stessi articoli sono ripetuti casualmente per ogni matrice. Quando un elemento viene inserito in ( i , j ), per le seguenti matrici l'articolo non può essere posizionato nella stessa riga o colonna.

For example:

A 3 × 3 matrix is repeated 3 times. We have 9 items (A, B, …, I). In the first step, I add A randomly to the matrix 1 to the position (1, 2). Now with the second matrix, A cannot be placed in column 1 or row 2, they need to be excluded from the randomly selected positions.

Esiste un algoritmo noto che posso utilizzare per questo o quali soluzioni puoi proporre?

    
posta user1532587 18.04.2016 - 13:10
fonte

2 risposte

1

Quello che intendevo con il mio commento era il seguente semplice algoritmo.

Let nN and V = {1, …, n} be your set of items. To generate n × n matrices M(1) , … M(n) with the desired property, pick the elements of M(1) randomly from V without repetition. Then generate M(i + 1) by rotating the rows and columns of M(i).

Con ruotando le righe della matrice M intendo che gli elementi della vecchia riga i diventano gli elementi della nuova riga i + 1 e gli elementi della vecchia riga n diventano gli elementi della nuova riga 1. La rotazione delle colonne avviene allo stesso modo.

Illustrato dall'esempio:

 A B C                                     G H I
 D E F     -----  rotate rows  ----->      A B C
 G H I                                     D E F

   |
 rotate
 columns
   |
   V

 C A B
 F D E
 I G H

Ho implementato una versione veloce di questo in C ++.

int
main()
{
  constexpr auto N = std::size_t {3};
  std::array<char, N * N> items;
  std::array<square_matrix<char, N>, N> matrices;
  auto rndeng = std::default_random_engine {std::random_device {}()};
  std::iota(std::begin(items), std::end(items), 'A');
  std::shuffle(std::begin(items), std::end(items), rndeng);
  std::copy(std::begin(items), std::end(items), std::begin(matrices.front()));
  for (auto& matrix : matrices)
    {
      matrix = matrices.front();
      rotate_rows(matrices.front());
      rotate_cols(matrices.front());
    }
  assert(is_valid(items, matrices));
  for (const auto& matrix : matrices)
    std::cout << matrix << '\n';
}

Dove il criterio di accettazione è definito in is_valid come questo

template <typename T, std::size_t N>
bool
is_valid(const std::array<T, N * N>& items,
         const std::array<square_matrix<T, N>, N>& matrices)
{
  for (const auto& item : items)
    {
      std::array<std::size_t, N> at_row;
      std::array<std::size_t, N> at_col;
      for (auto idx = std::size_t {}; idx < N; ++idx)
        {
          const auto at = find_item(matrices[idx], item);
          if (at == std::make_pair(N, N))
            return false;
          at_row[idx] = at.first;
          at_col[idx] = at.second;
        }
      for (auto i = std::size_t {}; i < N; ++i)
        {
          if (std::count(std::begin(at_row), std::end(at_row), i) != 1)
            return false;
          if (std::count(std::begin(at_col), std::end(at_col), i) != 1)
            return false;
        }
    }
  return true;
}

utilizzando la seguente funzione di aiuto find_item .

template <typename T, std::size_t N>
auto
find_item(const square_matrix<T, N>& matrix, const T& item)
{
  for (auto i = std::size_t {}; i < matrix.rows(); ++i)
    {
      for (auto j = std::size_t {}; j < matrix.cols(); ++j)
        {
          if (matrix(i, j) == item)
            return std::make_pair(i, j);
        }
    }
  return std::make_pair(matrix.rows(), matrix.cols());
}

Il codice per rotate_rows e rotate_cols è indicato qui.

template <typename T, std::size_t N>
void
rotate_rows(square_matrix<T, N>& matrix)
{
  for (auto j = std::size_t {}; j < matrix.cols(); ++j)
    {
      const auto temp = matrix(matrix.rows() - 1, j);
      for (auto i = std::size_t {matrix.rows() - 1}; i > 0; --i)
        matrix(i, j) = matrix(i - 1, j);
      matrix(0, j) = temp;
    }
}

template <typename T, std::size_t N>
void
rotate_cols(square_matrix<T, N>& matrix)
{
  for (auto i = std::size_t {}; i < matrix.rows(); ++i)
    {
      const auto temp = matrix(i, matrix.cols() - 1);
      for (auto j = std::size_t {matrix.cols() - 1}; j > 0; --j)
        matrix(i, j) = matrix(i, j - 1);
      matrix(i, 0) = temp;
    }
}

Infine, sto utilizzando il seguente semplice tipo square_matrix .

template <typename T, std::size_t N>
class square_matrix final
{
 private:

  std::array<T, N * N> data_;

 public:

  std::size_t rows() const noexcept { return N; }
  std::size_t cols() const noexcept { return N; }

  T&
  operator()(const std::size_t i, const std::size_t j)
  {
    assert((i < this->rows()) && (j < this->cols()));
    return this->data_[i * this->rows() + j];
  }

  const T&
  operator()(const std::size_t i, const std::size_t j) const
  {
    assert((i < this->rows()) && (j < this->cols()));
    return this->data_[i * this->rows() + j];
  }

  auto begin() { return this->data_.begin(); }
  auto end() { return this->data_.end(); }

  auto begin() const { return this->data_.begin(); }
  auto end() const { return this->data_.end(); }

};

template <typename T, std::size_t N>
std::ostream&
operator<<(std::ostream& os, const square_matrix<T, N>& mat)
{
  for (auto i = std::size_t {}; i < mat.rows(); ++i)
    {
      for (auto j = std::size_t {}; j < mat.cols(); ++j)
        os << ' ' << mat(i, j);
      os << '\n';
    }
  return os;
}

Se vuoi rendere il risultato meno prevedibile, puoi anche mescolare le matrici generate dopo aver finito.

    
risposta data 18.04.2016 - 15:49
fonte
0

Ci sono (n x m)! permutazioni degli elementi, che possiamo assegnare a ciascun indice:

1, 2, 3, ..., (n x m)!

Ad esempio, se abbiamo una matrice 2 x 2, avremo (2 x 2)! o 24 permutazioni:

 1. A B C D
 2. A B D C
 3. A C B D
 4. A C D B
 5. A D B C
 6. A D C B
 7. B A C D
 8. B A D C
 9. B C A D
10. B C D A
11. B D A C
12. B D C A
13. C A B D
14. C A D B
15. C B A D
16. C B D A
17. C D A B
18. C D B A
19. D A B C
20. D A C B
21. D B A C
22. D B C A
23. D C A B
24. D C B A

Quindi tutto ciò di cui abbiamo bisogno è selezionare casualmente (senza sostituzione) N di queste permutazioni, una per matrice. Vedi questa risposta per idee su come farlo.

Dopo aver selezionato gli indici delle permutazioni, ad esempio (1, 18, 23) per N = 3, puoi trovare le permutazioni corrispondenti come descritto in questa risposta .

    
risposta data 18.04.2016 - 15:44
fonte

Leggi altre domande sui tag