1213. 打开遗迹之门
Constraints
Time Limit: 1 secs, Memory Limit: 32 MB
Description
NightElf是一个古老的种族,在他们的遗迹上到处都有古NightElf的奇妙文字,这些文字都是一些十分美妙而复杂的符号。然而,现在的NightElf人早已不认识古文字了,因为古文字过于复杂,早在几十个世纪之前,他们就改用简单的英文字母来代替古代的文字符号,每个古文字符号对应一个英文字母。当然,正是因为对应关系渐渐的被人遗忘了,所以古代文字已经无法卒读了。除了这一点之外,古语同现代语没有任何区别。
有一天,探险家Arthas在一个古老的NightElf遗迹前面被一扇大门给拦住了。大门上用古NightElf文字刻着一句话。当地人告诉他,只有知道这句话的意思,解出一个谜题,才能进入这个遗迹。
于是,Arthas下决心要找出古文字和现代的英文字母之间的联系,理解出这句话的含义。然而这并不是一件轻松的工作。所幸,他的一个朋友是语言学家,告诉了他一些很重要的事实:
NightElf文字共有n(1<=n<=27)个字母。其中n-1个文字是有意义的,这n-1个文字在现代语中用小写英文字母a,b,c.....中的前n-1个表示。还有一个文字是分隔符。在句子中每两个单词之间有且只有一个分隔符,将单词隔开。另外,NightElf语言中每个单词有着非常丰富的意思,因此只有很少的单词。
当然,遗迹大门上的那一句话中的每个单词都应该是NightElf语言中的合法单词。于是Arthas便想通过了解NightElf语言中的所有单词,来试着找出句子的含义。
Input
第一行一个整数t,表示有t组数据。
每组数据第一行是两个整数n(1=<n<=27)和m(1=<m<=200),分别表示NightElf语言的字符数和句子的字符数。
接着一行有m个整数,每个整数都在1到n之间,且1到n中的每一个数都会出现。每个数代表一个古NightElf语言的文字符号,相同的数字表示相同的文字符号。
再来是一个整数q(1=<q<=200),表示NightElf语言的单词数。
接下来有q行,每行一个由现代语写出的(即用小写英文字母表示)单词。每个单词的长度不超过10。
Output
输出只有一行,是Arthas该句子分析的结果:
如果句子只有唯一的可能,将它翻译成现代语输出
如果没有任何可能的单词组合组成句子,输出No solution
如果句子有多种可能的组合,输出Cannot determine
Sample Input
1 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
Problem Source
ZSUACM Team Member
// Problem#: 1213
// Submission#: 3586094
// The source code is licensed under Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License
// URI: http://creativecommons.org/licenses/by-nc-sa/3.0/
// All Copyright reserved by Informatic Lab of Sun Yat-sen University
#include <stdio.h>
#include <string.h>
int n, m, q;
char num2str[30];
char words[205][11];
int wl[205];
char senChar[205];
int senNum[205];
int deli;
bool wordLength[11];
int answerNum;
bool anAns;
char ansNum2str[30];
int w[205][2];
int wn;
bool check() {
int sp = 0;
wn = 0;
if (senNum[0] == deli || senNum[m - 1] == deli) return false;
for (int i = 0; i < m; i++) {
if (senNum[i] == deli) {
if (!wordLength[i - sp]) return false;
w[wn][0] = sp;
w[wn][1] = i - 1;
wn++;
sp = i + 1;
}
}
if (!wordLength[m - sp]) return false;
w[wn][0] = sp;
w[wn][1] = m - 1;
wn++;
return true;
}
bool isOK(int numNow, int charNow) {
bool existChar[30];
memset(existChar, false, sizeof(existChar));
for (int i = 1; i <= n; i++) if (num2str[i] != '\0') existChar[num2str[i] - 'a'] = true;
for (int i = 0; i < wl[charNow]; i++) {
if (!((num2str[senNum[w[numNow][0] + i]] == '\0' && !existChar[words[charNow][i] - 'a']) || num2str[senNum[w[numNow][0] + i]] == words[charNow][i])) return false;
}
return true;
}
bool isOK2() {
int charNum[30];
memset(charNum, 0, sizeof(charNum));
for (int i = 1; i <= n; i++) if (num2str[i] != '\0') charNum[num2str[i] - 'a']++;
for (int i = 0; i < 30; i++) if (charNum[i] > 1) return false;
return true;
}
void DFS(int now) {
if (now == wn) {
for (int i = 0; i < 30; i++) ansNum2str[i] = num2str[i];
answerNum++;
return;
}
int nowLength = w[now][1] - w[now][0] + 1;
for (int i = 0; i < q; i++) {
if (wl[i] == nowLength && isOK(now, i)) {
char lastNum2str[30];
for (int j = 1; j <= n; j++) lastNum2str[j] = num2str[j];
for (int j = 0; j < wl[i]; j++) num2str[senNum[w[now][0] + j]] = words[i][j];
if (!isOK2()) {
for (int j = 1; j <= n; j++) num2str[j] = lastNum2str[j];
continue;
}
DFS(now + 1);
for (int j = 1; j <= n; j++) num2str[j] = lastNum2str[j];
}
}
}
int main() {
int caseNum;
scanf("%d", &caseNum);
while (caseNum--) {
scanf("%d%d", &n, &m);
for (int i = 0; i < m; i++) scanf("%d", senNum + i);
scanf("%d", &q);
memset(wordLength, false, sizeof(wordLength));
for (int i = 0; i < q; i++) {
scanf("%s", words[i]);
wl[i] = strlen(words[i]);
wordLength[wl[i]] = true;
}
answerNum = 0;
for (int i = 1; i <= n; i++) {
deli = i;
if (check()) {
memset(num2str, 0, sizeof(num2str));
anAns = false;
DFS(0);
if (answerNum >= 2) break;
}
}
if(answerNum == 0) printf("No solution\n");
else if (answerNum >= 2) printf("Cannot determine\n");
else {
for (int i = 0; i < m; i++) {
if (ansNum2str[senNum[i]] == '\0') printf(" ");
else printf("%c", ansNum2str[senNum[i]]);
}
printf("\n");
}
}
return 0;
}