Я не думаю, что здесь вам помогут вложенные циклы; Вы входите на территорию рекурсии. : -)
Проблема, которую вы задаете, сводится к этому. У вас есть список номеров, а также частоты этих номеров. Вы хотите придумать все уникальные способы, которыми вы можете выбрать некоторое количество копий каждого номера. Например, учитывая
2 2
3 4
5 2
Вы бы хотели
2 0 3 0 5 0
2 0 3 0 5 2
2 0 3 2 5 0
2 0 3 2 5 2
2 0 3 4 5 0
2 0 3 4 5 2
2 2 3 0 5 0
2 2 3 0 5 2
2 2 3 2 5 0
2 2 3 2 5 2
2 2 3 4 5 0
2 2 3 4 5 2
Если мы просто напишем показатели, то у нас будет
0 0 0
0 0 2
0 2 0
0 2 2
0 4 0
0 4 2
2 0 0
2 0 2
2 2 0
2 2 2
2 4 0
2 4 2
Итак, вопрос в том, как вы можете создать это. К счастью, есть действительно красивая рекурсивная формулировка для генерации этих чисел. Это выглядит примерно так. Мы хотим написать функцию AllSquares
, которая принимает список пар простых чисел и их кратностей, а затем возвращает все возможные произведения, которые можно сформировать из тех простых чисел, которые являются идеальными квадратами. Мы сделаем это индуктивно.
В нашем базовом случае, если вы предоставляете пустой список для AllSquares
, то существует ровно один квадратный продукт, то есть 1, пустой продукт элементов пустого списка.
Для индуктивного шага предположим, что у нас есть непустой список, первый элемент которого (простое число, кратность), а остальные элементы - «покой». Предположим, что мы рекурсивно вычисляем список «комбинаций», сформированный путем вызова AllSquares
для остальных элементов списка. Тогда для i = 0, 2, 4, ..., кратности, если вы возьмете элементы в списке и умножите их на основание i , вы получите новый список идеальных квадратов. Если вы возьмете объединение всех этих значений, вы получите все возможные идеальные квадраты, которые вы можете сформировать из чисел. Самое интересное в том, что это работает, даже если кратности нечетны, поскольку вы будете рассматривать только четные экспоненты.
Вот простой Java-код, который реализует этот алгоритм. Это совсем не эффективно, но оно имеет смысл:
private static List<Integer> allSquares(List<BaseMultiplicity> elems) {
/* Base case: If the list is empty, there's only one square. */
if (elems.isEmpty()) {
return Collections.singletonList(1);
}
/* Recursive case: Compute the answer for the rest of the list. */
List<BaseMultiplicity> rest = new LinkedList<BaseMultiplicity>(elems);
rest.remove(0);
List<Integer> recResult = allSquares(rest);
/* Now, for each even power of this number, add appropriately-scaled
* copies of the recursive solution to the result.
*/
List<Integer> result = new ArrayList<Integer>();
for (int i = 0, base = 1; i < elems.get(0).multiplicity;
i += 2, base *= elems.get(0).prime)
for (Integer elem: recResult)
result.add(elem * base * base);
return result;
}
Надеюсь, это поможет!