È possibile comprimere alcuni tipi di dati, come testo umano o codice sorgente, con grammatiche lineari. Fondamentalmente si crea una grammatica la cui lingua ha esattamente una parola: i dati non compressi. In questa attività, è necessario scrivere un programma che implementa questo metodo di compressione dei dati.
Ingresso
L'input è una stringa di lunghezza non superiore a 65535 byte. È garantito che l'input corrisponde all'espressione regolare [!-~]+
(ovvero almeno un carattere ASCII stampabile escluso lo spazio bianco).
Un esempio di input è
abcabcbcbcabcacacabcabab
Produzione
L'output è un insieme di regole che formano una grammatica che descrive esattamente una parola (input). Ciascun nonterminale è indicato da un numero decimale maggiore di 9. Il simbolo iniziale è il simbolo numero dieci. Di seguito viene fornito un output di esempio corrispondente all'input di esempio; la sua sintassi è descritta più avanti:
10=11 11 12 12 11 13 13 11 14 14
11=a 12
12=b c
13=a c
14=a b
Ogni regola ha la forma <nonterminal>=<symbol> <symbol> ...
con un numero arbitrario di simboli separati da spazi bianchi sul lato destro. Ogni output che rispetta le seguenti restrizioni e deriva esattamente la stringa di input è valido.
restrizioni
Per impedire alle persone di fare cose strane, si stanno verificando una serie di restrizioni:
Ogni nonterminale deve apparire almeno due volte sul lato destro di una regola. Ad esempio, la seguente grammatica per l'input
abcabc
è illegale perché la regola 12 appare una sola volta:10=12 11=a b c 12=11 11
Nessuna sequenza di due simboli adiacenti può apparire più di una volta in tutti i lati di destra di tutte le regole, tranne se si sovrappongono. Ad esempio, la seguente grammatica per l'input
abcabcbc
è illegale poiché la sequenzabc
appare due volte:10=11 11 b c 11=a b c
Una grammatica valida sarebbe:
10=11 11 12 11=a 12 12=b c
Il programma deve terminare in meno di un minuto per ogni input valido che non superi i 65535 byte.
Come al solito, non è possibile utilizzare alcuna funzionalità della propria lingua o alcuna funzione di libreria che renda banale la soluzione o ne implementi gran parte.
Input di esempio
Generare input di esempio con il seguente programma 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;
}
L'input di esempio generato dal programma sopra riportato di solito non porterà a buoni risultati di compressione. Prendi in considerazione l'utilizzo di testo umano o codice sorgente come input di esempio.
Criteri vincenti
Questo è il codice golf; vince il programma con il codice sorgente più breve. Per ulteriore credito, scrivere un programma che ricostruisce l'input dall'output.