Кодировать каждый элемент набора с простым номером.
Ex:
a -> 2
b -> 3
c -> 5
т.д.
Теперь вам нужно больше двух списков для поддержания.
Первый список для простых чисел, второй для их показателей.
Идея такова; когда вы натыкаетесь на элемент, записываете его простое число и сколько раз подряд оно появляется.
Для [a, b, b, c]
, вы получите это:
[2, 3, 3, 5]
который может быть записан как:
[2, 3^2, 5]
или, точнее:
[2^1, 3^2, 5^1]
и вы поддерживаете два списка:
[2,3,5] // primes in succession - list [p]
[1,2,1] // exponents - list [e]
Теперь вы перебираете эти два списка с концов на середину, проверяя, является ли первый элемент [p]^[e] таким же, как последний элемент; если он есть, то второй со следующим последним и т. д. ... Если все они одинаковы, ваш список можно уменьшить.
В этом примере вы проверяете, 2^1*5^1 == 3^2*3^2
; и поскольку это не так, его нельзя уменьшить.
Давайте попробуем [a, b, b, a, b, b]
:
Это кодируется как
[2^1, 3^2, 2^1, 3^2]
или
[2, 3, 2, 3] // primes
[1, 2, 1, 2] // exponents
Теперь мы проверяем, если 2^1 * 3^2 == 3^2 * 2^1
(первый премьер, первый показатель умножается на последний штрих, последний экспонента, а затем сравнивается со вторым против ближайшего к последнему)
Так как это имеет место, оно приводимо.
Давайте попробуем [b, b, b, b, b]
:
Это может быть закодирован как
[3^5]
или,
[3] // primes
[5] // exponents
Это особый случай: если у вас есть 1 списки элементов, то ваш исходный список можно привести.
Давайте попробуем [b, b, b, b, a]
:
Это может быть закодирован как
[3^4, 2^1]
или
[3, 2] // primes
[4, 1] // exponents
Мы проверяем 3^4 == 2^1
, и так как это не так, ваш список не приводим.
Давайте попробуем [a, b, a, b, a, b]
:
Это может быть закодирован как
[2^1, 3^1, 2^1, 3^1, 2^1, 3^1]
или,
[2, 3, 2, 3, 2, 3]
[1, 1, 1, 1, 1, 1]
Trying вышеописанную процедуру работает, потому что 2^1 * 3^1 == 3^1 * 2^1 == 2^1 * 3^1
Таким образом, алгоритм будет что-то вроде этого:
Кодировать все числа до простых чисел.
Итерация по списку, сделать два списка и заполнить их, как описано
Теперь, когда у вас есть два списка, p
и e
, оба из которых имеют длину n
сделать это:
var start = p[0]^e[0] * p[n-1]^e[n-1]
var reducible = true;
for (int i = 0; i < n/2, ++i) :
if ((p[i]^e[i] * p[n-i]^e[n-i]) != start) :
reducible = false;
break;
Примечание: Я не кодировал этот алгоритм и не тестировал его для различных входов. Это просто идея. Кроме того, если список является приводимым, из его длины и длины n
, не должно быть слишком сложно увидеть, как уменьшить исходный список до его основной формы.
Второе примечание: если кто-либо видит ошибку выше, пожалуйста, исправьте меня. Возможно, что ничего из этого действительно не работает, так как это поздно, и моя концентрация не оптимальна.
Каково ваше правило для непредубежденности `[a, b, b, c]` и `[b, b, b, b, a]`? И что такое интуиция? Я спрашиваю, потому что это выглядит как частные случаи более общего алгоритма. `[b, b]` будет (рекурсивно) сокращаться до `[b]`, как и `[b, b, b, b] -> [b]` вашим третьим правилом. – 2010-11-28 21:25:23
Что вы ищете - это алгоритм сжатия данных. Проверьте Хаффмана и арифметическое кодирование. – 2010-11-28 21:38:20
[a, b, b, c] -> [a, b, b, c] [b, b, b, b] b, b] -> [b] Все эти случаи сохраняют оригинальный плейлист, так как он зацикливается навсегда. – kiteloop 2010-11-29 21:16:21