1002. Phone Numbers

* 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.

1002. Phone Numbers_c语言

Accepted 

1002. Phone Numbers_git_02

CEOI'99 Problems