Комбинаторный вопрос - PullRequest
0 голосов
/ 13 мая 2011

У меня есть, как мне кажется, «перечислительный комбинаторный» вопрос.

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

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

Количество комбинаций с повторением для 7 из 15 составляет 116 280 (я дважды проверил, что это правильно).

Вот код:

public static void main(String[] args) {
    final Random r = new Random( System.currentTimeMillis() );
    final List<String> ls = new ArrayList<String>();
    for (int i = 0; i < 15; i++) {
        for (int j = i; j < 15; j++) {
            for (int k = j; k < 15; k++) {
                for (int l = k; l < 15; l++) {
                    for (int m = l; m < 15; m++) {
                        for (int n = m; n < 15; n++) {
                            for (int o = n; o < 15; o++) {
                                ls.add( i + " " + j + " " + k + " " + l + " " + m + " " + n + " " + o + ": " + r.nextLong() );
                            }
                        }
                    }
                }
            }
        }
    }
    System.out.println( "We have " + ls.size() + " entries" );
    System.out.println( "Entry @ 5,7,2,10,11,8,3 is " + getEntryAt(5,7,2,10,11,8,3) );
}

private static String getEntryAt( int i, int j, int k, int l, int m, int n, int o ) {
    return "FILL ME"; // What goes here ?
}

В приведенном выше примере я просто помещаю случайное значение в массив поиска, но это в основном так: я хочу получить, скажем, (5,7, 2,10,11,8,3), могу ли я легко «вычислить» его местоположение?

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

Есликто-нибудь знает, о чем я говорю, любая помощь будет очень кстати.

Ответы [ 5 ]

3 голосов
/ 13 мая 2011

Простой способ разбить его на части - сложить счет в виде частей.(Для моих примеров я использовал индекс на основе 1)

Допустим, вам дан кортеж (меньше цифр, но тот же принцип) (2, 3, 4).Его позиция - это просто сумма:

  • (1, x, y) - всех чисел, которые вписываются в это
  • (2, 2, x)
  • (2, 3, x) - где x <4 </li>

, и вы можете это выяснить итеративно.

Теперь, для D = 3 цифры и K элементов, вы можетевытяните шаблон и посмотрите, как он растет:

K = 1

1 1 1

K = 2

1 1 1
1 1 2

1 2 2

2 2 2

K = 3

1 1 1
1 1 2
1 1 3

1 2 2
1 2 3

1 3 3

2 2 2
2 2 3

2 3 3

3 3 3

для каждой итерации вы фактически берете предыдущие группировки (включая пустую группировку) и добавляете дополнительное число - как впоследовательность треугольных чисел.Вы даже можете думать об этом рекурсивно, увеличивая первую цифру - в приведенном выше примере с D = 3, K = 3 вы можете переназначить символы материала, который не начинается с «1», и, таким образом,они не содержат никаких «1» - D по-прежнему 3, но K теперь 2:

K = 3 (ignoring 1's)

2 2 2
2 2 3

2 3 3

3 3 3

становится:

K = 2

1 1 1
1 1 2

1 2 2

2 2 2

Это то, как вы бы добавили к K.(Для D = 3 обратите внимание, что это треугольные числа.)

Как насчет добавления цифры?Ну, для K = 3, D = 3, вы можете себе представить, учитывая это:

K = 3

1 1 1
1 1 2
1 1 3

1 2 2
1 2 3

1 3 3

2 2 2
2 2 3

2 3 3

3 3 3

и добавить цифру перед ними.Вы можете добавить «1» перед всеми ними.Вы можете добавить только «2» перед «2» или выше, и «3» к тому, у которого только «3».Теперь вы можете увидеть рекурсивную структуру.

Для простого примера, чтобы найти индекс (2, 4, 4) с D = 3, K = 5:

index( 2, 4, 4 ) =
   # number of leading 1's, and re-index
   index( 3, 3 ) + count( D = 2, K = 5 ) =
   index( 3, 3 ) + 15 =
   # number of leading 1's and 2's, and re-index
   index( 1 ) + count( D = 1, K = 4 ) + count( D = 1, K = 3 ) + 15 =
   index( 1 ) + 4 + 3 + 15 = index( 1 ) + 22 = 
   22

Такindex (2, 4, 4) = 22 * ​​1034 *

Теперь сложная часть вычисляет счет (D, K), который на самом деле просто C (K + D - 1, D).Теперь вы можете обобщить это на K = 15, D = 7.

// This is actually 0-based.
// Really should use an array or something to make it easy to generalize, 
// so I'm going to skip a lot of cut and paste
private static int getEntryAt( int i, int j, int k, int l, int m, int n, int o ) {
   int D = 7, K = 15;
   int total = 0;

   if ( i > 0 ) {
      for ( int index = 0; index < i; index++ ) {
         total += count( D, K - index );
      }
   }

   j -= i, k -= i, l -= i, m -= i, n -= i, o -= i;
   D--;
   K -= i;
   // repeat for j, k, ...

   return count;
}
0 голосов
/ 26 июля 2011

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

0 голосов
/ 07 июня 2011

Построить дерево высотой 7. Корневой узел имеет 15 дочерних элементов с именем 1-15.Каждое дочернее имя соответствует выбору этого номера в наборе.У узла с номером n есть дочерние элементы с номерами m (n <= m <= 15). На листьях дерева (все 116 280, все имеют глубину 7) вы связываете предварительно вычисленное решение для этой комбинации.</p>

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

0 голосов
/ 13 мая 2011
long[,,,,,,] ls = new long[15, 15, 15, 15, 15, 15, 15];

и в ваших глубоко вложенных циклах:

ls[i, j, k, l, m, n, o] = r.nextLong();

и для ваших операторов get это просто:

return ls[i, j, k, l, m, n, o];

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

0 голосов
/ 13 мая 2011

Похоже, вы хотите Map<Multiset,T>, где T - это тип ваших дорогих для вычисления значений.HashMap<Multiset,T> будет использовать массив для внутреннего использования, поэтому я думаю, что это правильный ответ.

Смысл превращения ключа в Multiset заключается в том, что метод equals() в мультимножестве должен учитывать два мультимножества длябыть равными, если они содержат одинаковые номера каждого элемента, независимо от порядка.(Кстати, JDK не имеет класса Multiset, но вы можете найти сторонние классы Multiset.)

...