148 - Anagram checker

148 - Anagram checker

Time limit: 3.000 seconds

It is often fun to see ifrearranging the letters of a name gives an amusing anagram. For example, theletters of `WILLIAM SHAKESPEARE' rearrange to form `SPEAK REALISM AWHILE'.

Write a program that will read ina dictionary and a list of phrases and determine which words from thedictionary, if any, form anagrams of the given phrases. Your program must findall sets of words in the dictionary which can be formed from the letters ineach phrase. Do not include the set consisting of the original words. If noanagram is present, do not write anything, not even a blank line.

Input

Input will consist of two parts.The first part is the dictionary, the second part is the set of phrases forwhich you need to find anagrams. Each part of the file will be terminated by aline consisting of a single#. The dictionary will be in alphabeticorder and will contain up to 2000 words, one word per line. The entire filewill be in upper case, and no dictionary word or phrase will contain more than20 letters. You cannot assume the language being used is English.

Output

Output will consist of a seriesof lines. Each line will consist of the original phrase, a space, an equal sign(=), another space, and the list of words that together make up an anagram ofthe original phrase, separated by exactly one space. These words must appear inalphabetic sequence.

Sample input

ABC
AND
DEF
DXZ
K
KX
LJSRT
LT
PT
PTYYWQ
Y
YWJSRQ
ZD
ZZXY
# 
ZZXY ABC DEF
SXZYTWQP KLJ YRTD
ZZXY YWJSRQ PTYYWQ ZZXY
#

Sample output

SXZYTWQP KLJ YRTD = DXZ K LJSRT PTYYWQ
SXZYTWQP KLJ YRTD = DXZ K LT PT Y YWJSRQ
SXZYTWQP KLJ YRTD = KX LJSRT PTYYWQ ZD
SXZYTWQP KLJ YRTD = KX LT PT Y YWJSRQ ZD

 


分析:
一种思路是采用递归式暴力搜索。这样的话,对代码性能的要求比较高,为了快速的判断一个短语是否包含某个单词,首先必须找出一种特定的数据结构来表示。
给每个单词附加一个26字节长度的数组,各个元素分别代表a, b, ..., z这26个字母在单词中出现的次数,把这个数组称为字符串的特征(简称特征)。对于短语也同样处理(忽略中间的空格),如果短语的特征均大于或等于某个单词的特征,即可判定该短语包含该单词。如果要在短语中删除或添加某个单词,只需对特征进行加减即可。
递归的过程是:从字典的第一个单词开始查找,找到第一个能被短语包含的单词,从短语特征中减掉这个单词并将该单词加入结果列表;然后将字典的起点移动到这个单词之后,开始下一级递归调用。如果下一级返回,则重新恢复原短语特征(再加上前面的单词)并从结果集中移除该单词,继续向字典后面查找。如果在某一级调用的开始发现短语特征已经减为0,则说明已经找到可以重组为该短语的单词集,按要求输出结果即可(注意排除单词集与短语中的单词列表完全重合的情况)。
在具体实现中,将结果集直接生成为字符串是为了使代码清晰,如果要追求效率应另用链表或双端队列来保存,以加快添加和删除的速度。



#include <stdio.h>

#include <string.h>


char dic[2001][21];
int dv[2001][27];
int dn;
char ph[21];
char phw[21][21];
int phwn;
int pv[27];
int len;


int ans[100];
int num;


int dfs(int n)
{
   if(n>=dn)return 0;


   int t=1;
   for(int i=0;i<26;i++)
   if(dv[n][i]>pv[i])
   {
       t=0;break;
   }


   if(t)
   {
       int t=1;
       for(int i=0;i<26;i++)
       if(dv[n][i]!=pv[i])
       {
           t=0;break;
       }
       if(t)
       {
           ans[num++]=n;
           int val[100];
           for(int i=0;i<num;i++)
           val[i]=1;
           int tt=0;
           //printf("%d\n",phwn);
           for(int i=0;i<phwn;i++)
           {
               int t=0;
               for(int j=0;j<num;j++)
               {
                   if(val[j])
                   {
                       if(strcmp(dic[ans[j]],phw[i])==0)
                       {
                           t=1;
                           val[j]=0;
                           break;
                       }
                   }
               }
               //printf("%d\n",t);
               if(t==0)
               {tt=1;break;}
           }


           num--;
           if(tt){
           printf("%s = ",ph);
           for(int i=0;i<num;i++)
           printf("%s ",dic[ans[i]]);
           printf("%s\n",dic[n]);
           }
       }


       for(int i=0;i<26;i++)
       pv[i]-=dv[n][i];
       ans[num++]=n;
       dfs(n+1);
       num--;
       for(int i=0;i<26;i++)
       pv[i]+=dv[n][i];
   }


   dfs(n+1);
}


int main()
{
    memset(dv,0,sizeof(dv));
    for(dn=0;dn<2001;dn++)
    {
        scanf("%s",dic[dn]);
        if(dic[dn][0]=='#')break;


        int len=strlen(dic[dn]);
        for(int j=0;j<len;j++)
        dv[dn][dic[dn][j]-'A']++;
    }
    while(1)
    {
        //len=1;
        memset(pv,0,sizeof(pv));
        memset(phw,0,sizeof(phw));


        gets(ph);


        len=strlen(ph);
        phwn=0;
        int j=0;
        for(int i=0;i<=len;i++)
        {
            if(i==len||ph[i]==' ')
            {
                phw[phwn++][j]='\0';
                j=0;
            }
            else
            phw[phwn][j++]=ph[i];
        }
        if(ph[0]=='#')break;
        //len=strlen(ph);


        for(int i=0;i<len;i++)
        {
            if(ph[i]==' ')continue;
            pv[ph[i]-'A']++;
        }


        num=0;
        dfs(0);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值