【题目描述】
有一天,小y突然发现自己的计算机感染了一种病毒!还好,小y发现这种病毒很弱,只是会把文档中的所有字母替换成其它字母,但并不改变顺序,也不会增加和删除字母。
现在怎么恢复原来的文档呢!小y很聪明,他在其他没有感染病毒的机器上,生成了一个由若干单词构成的字典,字典中的单词是按照字母顺序排列的,他把这个文件拷贝到自己的机器里,故意让它感染上病毒,他想利用这个字典文件原来的有序性,找到病毒替换字母的规律,再用来恢复其它文档。
现在你的任务是:告诉你被病毒感染了的字典,要你恢复一个字母串。
【输入】
第一行为整数K(≤50000),表示字典中的单词个数。
以下K行,是被病毒感染了的字典,每行一个单词。
最后一行是需要你恢复的一串字母。
所有字母均为小写。
【输出】
输出仅一行,为恢复后的一串字母。当然也有可能出现字典不完整、甚至字典是错的情况,这时请输出一个0。
【输入样例】
6
cebdbac
cac
ecd
dca
aba
bac
cedab
【输出样例】
abcde
代码:
#include <cstdio>
#include <cstring>
#include <vector>
#include <queue>
#include <map>
#include <algorithm>
#define MAXN 50005
using namespace std;
int n , cnt ;
int in[MAXN] , ans[MAXN] ;
bool flag ;
char have[MAXN] ;
string s[MAXN] , g ;
vector <int> G[MAXN] ;
map <char , int > T ;
void Topol() {
int count = 0 ;
int k = 0 ;
queue <int> q ;
for( int i = 1 ; i <= cnt ; ++ i )
if( !in[i] ) {
k ++ ;
q.push(i) ;
}
if( k != 1 ) {//拓扑序唯一
flag = 1 ;
return ;
}
while( !q.empty() ) {
int sum = 0 ;
int x = q.front() ;
q.pop() ;
count ++ ;
ans[x] = count ;
for( int i = 0 ; i < G[x].size() ; ++ i ) {
int s = G[x][i] ;
in[s] -- ;
if( !in[s] ) {
q.push(s);
sum ++ ;
}
}
if( sum > 1 ) {//保证拓扑序唯一
flag = 1 ;
return ;
}
}
if( count != cnt )//拓扑跑完了的
flag = 1 ;
return ;
}
int main() {
scanf("%d", &n );
for( int i = 1 ; i <= n ; ++i )
cin >> s[i] ;
cin >> g ;
for( int i = 2 ; i <= n ; ++ i ) {
for( int j = 0 ; j < min( s[i].length() , s[i-1].length() ) ; ++j ) {
if( !T[s[i][j]] ) {//map存储
cnt ++ ;
T[s[i][j]] = cnt ;
have[cnt] = s[i][j] ;//记录出现了的字母
}
if( !T[s[i-1][j]] ) {
cnt ++ ;
T[s[i-1][j]] = cnt ;
have[cnt] = s[i-1][j] ;
}
if( s[i-1][j] != s[i][j] ) {//连边
int a = T[s[i-1][j]] ;
int b = T[s[i][j]] ;
G[a].push_back(b) ;
in[b] ++ ;
break ;
}
}
}
Topol();
if( flag ) {
printf("0");
return 0;
}
sort( have+1 , have+cnt+1 );//排序
for( int i = 0 ; i < g.length() ; ++ i ) {//是否有没出现的字母
int now = T[g[i]];
if( now == 0 ) {
printf("0");
return 0;
}
}
for( int i = 0 ; i < g.length() ; ++ i ) {//找正确的字母
int now = T[g[i]];
int rig = ans[now] ;
printf("%c", have[rig] );
}
}