遗迹之门

来源:互联网 发布:adobe cs6 注册机 mac 编辑:程序博客网 时间:2024/06/08 00:10


Description

NightElf 是一个古老的种族,在他们的遗迹上到处都有古NightElf 的奇妙文字,这些文字都是一些十分美妙而复杂的符号。然而,现在的NightElf 人早已不认识古文字了,因为古文字过于复杂,在几十个世纪前,他们就改用简单的英文字母来代替古代的文字符号,每个古文字符号对应一个英文字母。当然,正是因为对应关系渐渐被人遗忘、,所以古代文字已经无法阅读。除了这一点之外,古语同现代语没有任何区别。有一天,探险家Arthas 在一个古老的NightElf 遗迹前面被一扇门给拦住了。大门上用NightElf 文字刻着一句话。当地人告诉他,只有知道这句话的意思,解出一个谜题,才能进入这个遗迹。 

于是 Arthas 下决心要找出古文字和现代的英文字母之间的联系,理解这句话的含义。然而这并不是一件轻松的工作。所辛,他的一个朋友是语言学家,告诉他一些很重要的事实:NightElf 文字共有n(1<=n<=27)个文字符号。其中n-1 个文字是有意义的,这n-1 个文字在现代语中用小写字母a,b,…中的前 n-1 个表示。还有一个文字是分隔符。 

在句子中每个单词之间有且仅有一个分隔符,将单词隔开。另外NightElf 语言中的合法单词有着非常丰富的意义。因此只有很少的单词。当然,遗迹之门上的那一句话的每个单词都应该是NightElf 语言中的合法单词。于是Arthas想通过了解NightElf 语言中的所有单词,来试着找出句子的含义。

Input

第一行一个整数 t,表示有t 组测试数据。 
每组数据第一行是两个整数n(1<=n<=27)和m(1<=m<=150),分别表示NightElf 语言的字符数和句子的字符数。 
接着一行有 m 个整数,每个整数都在1 到n 之间,且1 到n 中的每一个数都会出现。每个数代表一个古NightElf 语言的文字符号,相同的数字表示相同的文字符号。 
再接下来一个整数q(1<=q<=200),表示NightElf 语言的单词数。 
接下来有 q 行,每行一个有现代语写出的(即用小写字母表示)单词。每个单词的长度不超过10。

Output

输出一行,是 Arthas 对输入古文的分析结果: 
1)如果句子只有惟一的可能,将它翻译成现代语输出; 
2)如果没有任何可能的单词组合组成句子,输出No solution; 
3)如果句子有多种可能的组合,输出Cannot determine。

Sample Input

 

5 18 
3 2 1 3 5 4 2 1 1 5 2 4 3 4 5 3 4 1 
14 
adca 
bacb 
cacc 
adba 
cabb 
bdcc 
dacc 
baaa 
dbab 
acbc 
daba 
cba 
abc 
dcb

 

Sample Output

 

adca bdcc dbab abc

 

Hint

40%的数据满足: t=1,n<=6,m<=30,q<=40 
100%的数据满足: t<=3,n<=27,m<=150,q<=200


【分析】

 

    寻找集合{1,2,}与集合{a,b,}的一一对应关系,实质是一个排列生成问题。

    Step1确定分隔符(空格),需要穷举每个数字能否作为空格,原则是:一旦确定i是空格,则特殊的语言中分出来形成单词的长度要在单词表中出现才行。这可以排除显然无解的情况:例如样例中,以1作为空格,则第一个单词为3 2,而单词表中没有长度为2的单词。

    Step2搜索对应关系: 

    搜索策略1:用排列搜索出一种对应关系,再判断是否合法,时间复杂度O(n!)

    搜索策略2:按照给出的特殊语言a[1]..a[m]的顺序进行搜索对应关系,这样的搜索顺序为我们剪枝提供了方便:

    剪枝搜索单词的时候,用一个数组建立对应关系,若发现当前字母与之前的对应关系有冲突,剪枝。

    这个剪枝相当强,只需这个剪枝便可以100ms左右过了。


【代码】

#include<cstdio>#include<cstdlib>#include<cstring>#include<cmath>#include<ctime>#include<iostream>#include<algorithm>using namespace std;int T,N,M,Nt,ANS,v[300],Q;string w[300],s;char match[30],path[30];  //path数组记录答案bool f[30];int ans;void _DFS(int k){    if(k>M)    {        memcpy(path,match,sizeof(match));        ans++;        ANS=N;       //记录取得答案的分隔符        return;    }    bool ft[30];    char mt[30];    memcpy(ft,f,sizeof(f));    memcpy(mt,match,sizeof(match));    for(int i=1;i<=Q;i++)    {         memcpy(f,ft,sizeof(ft));         memcpy(match,mt,sizeof(mt));         int j,p=1;         for(j=k;v[j]!=N&&j<=M;j++);         j--;         if((j+1-k)!=w[i].length())             continue;         for(int o=k;o<=j;o++)         {             int oi=o+1-k;             //剪枝             if((('a'<=match[v[o]]&&match[v[o]]<='z')||(f[w[i][oi-1]-'a']==true))&&match[v[o]]!=w[i][oi-1])             {                 p=0;                   break;             }             match[v[o]]=w[i][oi-1];             f[w[i][oi-1]-'a']=true;         }         if(p==0)             continue;          _DFS(j+2);          if(ans>=2)              return;    }  }void _init(){    ans=0;    memset(path,0,sizeof(path));  //注意初始化数组    memset(v,0,sizeof(v));    scanf("%d%d",&N,&M);    for(int i=1;i<=M;i++)        scanf("%d",&v[i]);    scanf("%d",&Q);    for(int i=1;i<=Q;i++)        cin>>w[i];    Nt=N;}void _solve(){    for(N=1;N<=Nt;N++)     //枚举哪个数字作为分隔符    {              for(int i=1;i<=Q;i++)       {            int j,p=1;             memset(match,0,sizeof(match));             memset(f,0,sizeof(f));             for(j=1;v[j]!=N;j++);             j--;             if(j!=w[i].length())                 continue;             for(int o=1;o<=j;o++)             {                 if((('a'<=match[v[o]]&&match[v[o]]<='z')||(f[w[i][o-1]-'a']==true))&&match[v[o]]!=w[i][o-1])                 {                     p=0;                     break;                 }                 match[v[o]]=w[i][o-1];                 f[w[i][o-1]-'a']=true;             }             if(p==0) continue;              _DFS(j+2);              if(ans>=2)              {                  printf("Cannot determine\n");                  return;              }         }    }    if(ans)    {        for(int i=1;i<=M;i++)        {            if(v[i]==ANS)                printf(" ");            else if('a'<=path[v[i]]&&path[v[i]]<='z')                printf("%c",path[v[i]]);        }        printf("\n");    }    else       printf("No solution\n");}int main(){   scanf("%d",&T);   for(int i=1;i<=T;i++)   {       _init();       _solve();   }   return 0;}