URAL->1002. Phone Numbers

题目链接:http://acm.timus.ru/problem.aspx?space=1&num=1002

  写的比较疼的一个题。做法是trie+dp,dp很裸,不是难点。主要是对于trie不太会的同学写起来比较费劲。算是trie的入门题吧。

解法之一就是先把主串转换成字符串,在把字典按照对应的数字转换,插入到trie中。然后对主串每个位置枚举,如果从i+1开始长j的字串存在于字典中,则d[i+j]=min(d[i+j],d[i]+1),剩下来就很好写了。

  有一个需要注意的地方就是题目说可能存在多个解求出人一个均可,如果是test3 wa了就注意下这个地方。

#include <iostream>
#include <cmath>
#include <cstring>
#include <cstdio>
#include <algorithm>

using namespace std;

struct trie{
    trie *next[26];
    int index;
};

inline trie *newnode(){
    trie *t;
    t=(trie*)malloc(sizeof(trie));
    memset(t,0,sizeof(trie));
    t->index=-1;
    return t;
}

void insert(trie *s, char x[], int pos){
    int i;
    trie *t;
    for(i=0; x[i]; i++){
        if(s->next[x[i]-'a'])s=s->next[x[i]-'a'];
        else{
            t=newnode();
            s->next[x[i]-'a']=t;
            s=t;
        }
    }
    s->index=pos;
}

void del_trie(trie * s){
    int i;
    for(i=0; i < 26 ;i++){
        if(s->next[i])
            del_trie(s->next[i]);
    }
    free(s);
    s=NULL;
}

int find(trie *s, char x[]){
    int i;
    if(x[0] == 0) return -1;
    for(i=0; x[i]; i++){
        if(s->next[x[i]-'a'])s=s->next[x[i]-'a'];
        else break;
    }
    if(x[i]==0)return s->index;
    else return -1;
}

char str[120], dict[50005][60];
char change[30];

/*
1 ij    2 abc   3 def
4 gh    5 kl    6 mn
7 prs   8 tuv   9 wxy
        0 oqz
*/
void init(){
        change[0]=change[1]=change[2]='c';
        change[3]=change[4]=change[5]='d';
        change[6]=change[7]='e';
        change[8]=change[9]='b';
        change[10]=change[11]='f';
        change[12]=change[13]='g';
        change[15]=change[17]=change[18]='h';
        change[19]=change[20]=change[21]='i';
        change[22]=change[23]=change[24]='j';
        change[14]=change[16]=change[25]='a';
}

int d[120], v[120];

int main(){

    int n, i, j, max_len, l, length;
    init();
    char temp[60];

    while (scanf("%s", str)!=EOF){

        if (!strcmp(str, "-1"))break;

        length = strlen(str);
        for (i=0; i<length; i++)
            str[i]=char(str[i]-'0'+'a');

        trie *T=newnode();
        scanf("%d", &n);
        max_len=0;

        for (i=0; i<n; i++){
            scanf("%s", dict[i]);

            l=strlen(dict[i]);
            max_len=max(max_len, l);

            for (j=0; j<l; j++)
                temp[j]=change[dict[i][j]-'a'];
            temp[j]='\0';
            insert(T, temp, i);
        }

        memset(d, -1, sizeof(d));
        d[0] = 0;

        for (i=0; i<=length; i++)
            if (d[i] > -1){

                memset(temp, '\0', sizeof(temp));
                for (j=1; j<=max_len; j++){

                    if (i+j > length)break;
                    temp[j-1]=str[i+j-1];
                    int t=find(T, temp);

                    if (t > -1){
                        if (d[i+j]==-1 ||d[i+j] > d[i]+1){
                            d[i+j] = d[i]+1;
                            v[i+j] = t;
                        }
                    }
                }
            }

        if (d[length]==-1)printf("No solution.\n");
        else {
            int p[100], k=0, now=d[length], j = length;
            p[k++]=v[length];
            for (i=length-1; i>= 1; i--){
                if (d[i] == now-1 && j-i==strlen(dict[v[j]])){
                    p[k++]=v[i];
                    now=d[i];
                    j=i;
                }
            }
            for (i = k-1; i>=0; i--){
                printf("%s", dict[p[i]]);
                if (i>0)printf(" ");
            }
            printf("\n");
        }

        del_trie(T);
    }
    return 0;
}
posted @ 2011-08-19 18:55  like@neu  阅读(302)  评论(0编辑  收藏  举报