Можно сжимать некоторые виды данных, такие как человеческий текст или исходный код, с помощью линейных грамматик. Вы в основном создаете грамматику, язык которой содержит ровно одно слово - несжатые данные. В этой задаче вы должны написать программу, которая реализует этот метод сжатия данных.
вход
Входные данные представляют собой строку длиной не более 65535 байтов. Гарантируется, что входные данные соответствуют регулярному выражению [!-~]+
(т. Е. Хотя бы одному печатному символу ASCII, исключая пробел).
Пример ввода
abcabcbcbcabcacacabcabab
Вывод
Выходные данные представляют собой набор правил, которые образуют грамматику, которая описывает ровно одно слово (входные данные). Каждый нетерминал обозначается десятичным числом больше 9. Начальный символ - символ номер десять. Пример вывода, соответствующий примеру ввода, приведен ниже; его синтаксис описан ниже:
10=11 11 12 12 11 13 13 11 14 14
11=a 12
12=b c
13=a c
14=a b
Каждое правило имеет форму <nonterminal>=<symbol> <symbol> ...
с произвольным количеством символов, разделенных пробелами, с правой стороны. Каждый вывод, который подчиняется следующим ограничениям и получает именно входную строку, является действительным.
ограничения
Для того, чтобы люди не могли совершать странные поступки, существует ряд ограничений:
Каждый нетерминал должен появляться как минимум дважды с правой стороны правила. Например, следующая грамматика для ввода
abcabc
недопустима, потому что правило 12 появляется только один раз:10=12 11=a b c 12=11 11
Никакая последовательность из двух соседних символов не может появляться более одного раза во всех правых частях всех правил, кроме случаев, когда они перекрываются. Например, следующая грамматика для ввода
abcabcbc
недопустима, так как последовательностьbc
появляется дважды:10=11 11 b c 11=a b c
Действительная грамматика будет:
10=11 11 12 11=a 12 12=b c
Ваша программа должна завершиться менее чем за одну минуту для каждого допустимого ввода, который не длиннее 65535 байт.
Как обычно, вы не можете использовать какие-либо средства вашего языка или библиотечные функции, которые делают решение тривиальным или реализуют его большую часть.
Пример ввода
Сгенерируйте ввод образца с помощью следующей программы на языке C.
#include <stdlib.h>
#include <stdio.h>
int main(int argc, char **argv) {
unsigned int i,j = 0,k;
if (argc != 3
|| 2 != sscanf(argv[1],"%u",&i)
+ sscanf(argv[2],"%u",&k)) {
fprintf(stderr,"Usage: %s seed length\n",argv[0]);
return EXIT_FAILURE;
}
srand(i);
while(j < k) {
i = rand() & 0x7f;
if (i > 34 && i != 127) j++, putchar(i);
}
return EXIT_SUCCESS;
}
Пример ввода, сгенерированный программой выше, обычно не приводит к хорошим результатам сжатия. Рассмотрите возможность использования человеческого текста или исходного кода в качестве примера ввода.
Критерии победы
Это код гольф; программа с самым коротким исходным кодом выигрывает. Для дополнительного кредита напишите программу, которая восстанавливает входные данные из выходных данных.
источник
Ответы:
GolfScript,
111108 символовЭто довольно неуклюжий подход с использованием GolfScript. Вторая версия работает намного лучше, чем начальная. Это намного длиннее, чем предполагалось, но моя реализация имела вложенные циклы do, и это вызывало проблемы с интерпретатором.
Примеры:
источник
Убрано - алгоритм не может обрабатывать все случаи.
C, 422 (исправлено, чтобы убрать дубликаты на выходе и пропущенный символ)Начальная реализация, начнется игра в гольф.
Так как правила не требуют, чтобы это фактически сжимало этот грубый наивный подход, подойдет ...
Может обработать длину 65535 в течение 10 секунд
Образец прогона:
источник