Матч 379, Телеигра (TVGameWinnings)

Дивизион 2, Уровень 3

 

Имеется коробка размера n * n, содержащая набор домино. В строке i и столбце j коробки находится кость домино, на которой изображены числа i и j. Игрок выбирает n костей домино так, чтобы ни с какой строки и ни с какого столбца не было взято более одной кости. Далее по правилам домино он должен сложить из них цикл. Например, при n = 4 можно выбрать 4 кости и сложить из них цикл: (1,3), (3,2), (2,4), (4,1). При описанном выше условии n костей домино всегда можно однозначно сложить в один или несколько циклов.

На каждой кости домино, находящейся  в строке i и столбце j, сзади написано число board[i][j]. Символы массива board от ‘0’ до ‘9’ представляют собой числа от 0 до 9, а символы от ‘A’ до ‘I’ представляют собой числа от -1 до -9. Вычислим произведение этих чисел для всех n выбранных костей домино. Если количество циклов (сложенных групп костей домино) четное количество, то следует умножить полученное произведение на -1. Полученное число является количеством выигранных (или в случае отрицательного числа проигранных) денег.

Необходимо найти наихудший (наименьший) и наилучший (наибольший) результат игры и вернуть их в виде массива из двух элементов.

 

Класс: TVGameWinnings

Метод:  vector<int> getMinMax(vector<string> board)

Ограничения: board содержит от 1 до 6 элементов, board[i] содержит элементов ‘0’ – ‘9’,’A’-‘I’.

 

Вход. Массив board описывает числа, изображенные сзади на костях домино.

 

Выход. Массив, содержащий наихудший и наилучший результат игры.

 

Пример входа

board

{"35",

"44"}

{"00200",

"0B000",

"00020",

"10000",

"00001"}

{"12A",

"A12",

"2A1"}

 

Пример выхода

{-12, 20}

{-8, 0}

{-1, 8}

 

РЕШЕНИЕ

перебор вариантов

 

Наибольший возможный размер доски равен 6, следовательно число вариантов выбрать n костей домино не более 6! = 720. Перебираем все перестановки из n чисел при помощи функции next_permutation. Каждой перестановке (a1, a2, …, an) соответствует выборка костей домино (board[1][a1], board[2][a2], …, board[n][an] ). Для каждой выборки (перестановки) считаем количество циклов, вычисляем произведение чисел board[i][ai]. Если количество циклов четно, умножаем произведение на -1.  Изо всех результатов игры находим в переменной min наихудший и в переменной max наилучший.

Функция getConnectedComponents(perm) вычисляет количество циклов в перестановке perm.

 

ПРОГРАММА

 

#include <cstdio>

#include <vector>

#include <algorithm>

#include <string>

using namespace std;

 

int m[7][7];

 

int getConnectedComponents(vector<int> perm)

{

  int i, j, temp, groups;

  for(groups = i = 0; i < perm.size(); i++)

  {

    j = i; groups += (perm[j] >= 0);

    while(perm[j] >= 0)

      temp = perm[j], perm[j] = -1, j = temp;

  }

  return groups;

}

 

class TVGameWinnings

{

public:

  vector<int> getMinMax(vector<string> board)

  {

    vector<int> res(2,0), perm(board.size(),0);

    int s, i, j, min, max;

    for(i = 0; i < board.size(); i++)

      for(j = 0; j < board[0].size(); j++)

        if (isdigit(board[i][j])) m[i][j] = board[i][j] - '0';

        else m[i][j] = -(board[i][j] - 'A' + 1);

    for(i = 0; i < board.size(); i++) perm[i] = i;

    min = 1000000000; max = -min;

    do

    {

      for(s = 1, i = 0; i < perm.size(); i++)

        s *= m[i][perm[i]];

      i = getConnectedComponents(perm);

      if (i % 2 == 0) s =-s;

      if (s < min) min = s;

      if (s > max) max = s;

    } while(next_permutation(perm.begin(),perm.end()));

    res[0] = min; res[1] = max;

    return res;

  }

};