* phone.c
/* https://acm.timus.ru/problem.aspx?space=1&num=1002 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifndef ENOMEM
#define ENOMEM 12
#endif
#ifndef off_t
typedef long int off_t;
#endif
struct word {
struct word *next; /* next word */
unsigned long len; /* word length */
char x[1]; /* word string */
};
#define INF 10000
#define HASHSIZ 0x2000 /* 8192 HASH-1=0x1fff */
static struct word *HashTable[HASHSIZ];
static char *heap = NULL;
static unsigned char cvt[] = "@22233344115566070778889990@@@@@";
/* "abcdefghijklmnopqrstuvwxyz" */
#define CHAR2DIGIT(c) (cvt[c & 0x1f])
static char *word_digits(const struct word *w) {
int i;
char *d = (char *)malloc(w->len+1);
for (i = 0; i < w->len; i++) {
d[i] = CHAR2DIGIT(w->x[i]);
}
d[i] = '\0';
return d;
}
static void *mjalloc(unsigned long size) {
static char *t;
static size_t rest = 0;
if (rest < size) {
rest = 16384;
heap = malloc(rest);
if (!heap) {
fprintf(stderr, "Out of memory!\n");
exit(ENOMEM); /* 12 */
}
}
t = heap;
heap += size;
rest -= size;
return t;
}
/* Word hash */
static unsigned int hash_fn(unsigned char b[], unsigned int l) {
unsigned int i = l;
while (l--) {
i = i*17 + CHAR2DIGIT(*b); /* 'a' 0x61 & 0x1f => 0x01 ( 1), cvt[1]='2'
'z' 0x7a & 0x1f => 0x1a (26), cvt[26]='0' */
b++;
}
return i & (HASHSIZ - 1);
}
/* Digits hash */
static unsigned int hash2(unsigned char b[], unsigned int l) {
unsigned int i = l;
while (l--) {
i = i*17 + *b++;
}
return i & (HASHSIZ - 1);
}
static off_t get_line(FILE *f, char *b) {
off_t off = 0;
fgets(b, 255, f);
while (off < 255 && b[off]!=0x0d && b[off]!=0x0a) {
off++;
}
b[off] = 0x00;
return off;
}
#define ARRSZ(a) (sizeof(a)/sizeof(a[0]))
#define E_OK 0
#define E_FAIL (-1)
/**
* Read first line digits, create HashTable.
* @param in char[] "69841225686237"
* @param in_len off_t *
* @return
*/
static int read_input(char in[], off_t *in_len, FILE *f) {
int i, n;
unsigned int h; /* hash code */
struct word *w;
unsigned char buf[256];
unsigned long le;
*in_len = get_line(f, in); /* Read the first line into var "in" */
if (in[0]=='-' && in[1] == '1') { /* END with -1 */
return E_FAIL;
}
fscanf(f, "%d\n", &n);
if (n < 1) {
return E_FAIL;
}
#ifndef ONLINE_JUDGE
printf("in=[%s], n=%d\n", in, n);
#endif
memset(HashTable, 0, sizeof(struct word *) * HASHSIZ);
for(i = 0; i < n && !feof(f); i++) {
get_line(f, (char *) buf);
le = strlen((char *)buf);
w = mjalloc(sizeof(struct word) + le);
w->len = le;
h = hash_fn(buf, le);
w->next = HashTable[h]; /* LIST_INSERT_HEAD */
HashTable[h] = w;
strcpy(w->x, (char *)buf);
}
#ifndef ONLINE_JUDGE
le = ARRSZ(HashTable);
char *d;
for (i = 0; i < le; i++) {
if (!HashTable[i]) { continue; }
printf("HashTable[%d] =", i);
for (w = HashTable[i]; w != NULL; w = w->next) {
d = word_digits(w);
printf(" \"%s\"(%s)", w->x, d);
free(d);
}
printf("\n");
}
#endif
return E_OK;
}
static struct word *find(char *pos, unsigned int l) {
int h = hash2((unsigned char *)pos, l);
struct word *words = HashTable[h];
char *x, *y;
#ifndef ONLINE_JUDGE
char *dbg = (char *)malloc(l + 1);
memset(dbg, 0, l + 1);
strncpy(dbg, pos, l);
printf("finding \"%s\",l=%u,hash=[%d]\n", dbg, l, h);
free(dbg);
struct word *node = words;
while (node) {
printf(" \"%s\"", node->x);
node = node->next;
}
printf("\n");
#endif
while (words) {
if (words->len == l) {
x = pos;
y = words->x;
while (*y && *x == CHAR2DIGIT(*y)) {
x++, y++;
}
if (!*y) { return words; }
}
words = words->next;
}
return NULL;
}
static void solve(struct word *prev[], int count[], char *digits, unsigned long len) {
unsigned long i, j;
struct word *w = NULL;
count[0] = 0;
for(i=1; i <= len; i++) {
count[i] = INF;
}
for(i=0; i < len; i++) {
if (count[i] >= INF) {continue;}
for(j=i+1; j <= len; j++) {
w = find(digits + i, j - i);
if (!w) {continue;}
#ifndef ONLINE_JUDGE
printf("FOUND \"%s\"\n", w->x);
#endif
if (count[j] > count[i] + 1) {
count[j] = count[i] + 1;
prev[j] = w;
}
}
}
}
static void wrr(FILE *f, unsigned long l, struct word *prev[]) {
struct word *w = prev[l];
if (!w) {
#ifndef ONLINE_JUDGE
printf("prev[%lu] is NULL\n", l);
#endif
return;
}
l -= w->len;
if (l) {
wrr(f, l, prev);
fputc(' ', f);
}
fputs(w->x, f);
}
void write_output(const int count[], unsigned long l, struct word *prev[], FILE *g) {
if (count[l] < INF) {
wrr(g, l, prev);
fputc('\n', g);
} else {
fprintf(g, "No solution.\n");
}
}
/* https://www.fi.muni.cz/ceoi1999/phone/ */
int main(void)
{
char digits[256] = {'\0'};
off_t in_len; /* "69841225686237".length */
struct word *prev[256] = {NULL};
int count[256];
#ifndef ONLINE_JUDGE
FILE *f = fopen("phone.in", "r");
if (!f) {return 2;}
FILE *g = fopen("phone.out", "w");
if (!g) { return 3; }
#else
FILE *f = stdin;
FILE *g = stdout;
#endif
/* @ref: https://acm.timus.ru/help.aspx?topic=cpp */
while (E_OK == read_input(digits, &in_len, f)) {
#ifndef ONLINE_JUDGE
printf("digits=\"%s\", in_len=%lu\n", digits, in_len);
#endif
memset(prev, 0, sizeof(struct word *)* ARRSZ(prev));
memset(count, 0, sizeof(int)* ARRSZ(count));
solve(prev, count, digits, in_len);
write_output(count, in_len, prev, g);
}
fclose(f);
fclose(g);
return 0;
}
* Makefile
CC=gcc
CFLAGS=-g -static -Wl,-s,--stack=67108864
TARGETS=phone
all: ${TARGETS}
${TARGETS}: phone.o
${CC} phone.o -lm -o $@
main.o: phone.c
${CC} ${CFLAGS} -c phone.c -o $@
clean:
rm -f ${TARGETS} phone.o core.* phone.out
test:
ulimit -c 10485760
./phone
* phone.in
7325189087
5
it
your
reality
real
our
4294967296
5
it
your
reality
real
our
-1
$ cat phone.out
reality our
No solution.
Accepted