1396:病毒(virus)
时间限制: 1000 ms 内存限制: 65536 KB
【题目描述】
有一天,小y突然发现自己的计算机感染了一种病毒!还好,小y发现这种病毒很弱,只是会把文档中的所有字母替换成其它字母,但并不改变顺序,也不会增加和删除字母。
现在怎么恢复原来的文档呢!小y很聪明,他在其他没有感染病毒的机器上,生成了一个由若干单词构成的字典,字典中的单词是按照字母顺序排列的,他把这个文件拷贝到自己的机器里,故意让它感染上病毒,他想利用这个字典文件原来的有序性,找到病毒替换字母的规律,再用来恢复其它文档。
现在你的任务是:告诉你被病毒感染了的字典,要你恢复一个字母串。
【输入】
第一行为整数K(≤50000),表示字典中的单词个数。
以下K行,是被病毒感染了的字典,每行一个单词。
最后一行是需要你恢复的一串字母。
所有字母均为小写。
【输出】
输出仅一行,为恢复后的一串字母。当然也有可能出现字典不完整、甚至字典是错的情况,这时请输出一个0。
【输入样例】
6
cebdbac
cac
ecd
dca
aba
bac
cedab
【输出样例】
abcde
【解析】
详见代码:
#include <bits/stdc++.h>
using namespace std;
int k,n=0;
string a[50005];//存字典
int du[30];//du[i]表示第i个字母的度
bool g[30][30];//邻接矩阵存边
int ans[30];//对应关系
int sx=0;//
void dfs(int x){
ans[x]=sx;//记录对应关系
sx++;
for(int i=0;i<=n;i++){//遍历所有边
if (g[x][i]==1){
du[i]--;//子节点入度减1
if (du[i]==0){//如果入度为0,加入拓扑排序序列,继续深搜
dfs(i);
}
}
}
}
int main() {
cin>>k;
for(int i=1;i<=k;i++){//输入字典
cin>>a[i];
}
for(int i=2;i<=k;i++){
for(int j=0;j<a[i-1].size();j++){
if (a[i].size()==j){//后边单词是前面的单词的前缀
cout<<0;//矛盾,输出0
return 0;
}
if (a[i][j]!=a[i-1][j]){//找到一条边(字母大小关系)
int u=a[i][j]-'a';
int v=a[i-1][j]-'a';
//邻接矩阵
g[v][u]=1;
if (g[u][v]==1){//如果存在反向边
cout<<0;//矛盾。输出0
return 0;
}
du[u]++;//度增加1
n=max(n,u);//取最大字母
n=max(n,v);//取最大字母
break;
}
}
}
int s=-1;
for(int i=0;i<=n;i++){//找度为0的拓扑排序起点
if (du[i]==0){
if (s!=-1){//如果有多个度为零的节点,矛盾,输出0
cout<<0;
return 0;
}
s=i;//记录起点
}
}
dfs(s);//从起点开始拓扑排序
string ss;//输入被感染的单词
cin>>ss;
for(int i=0;i<ss.size();i++){//逐字翻译
int x=ss[i]-'a';
ss[i]=ans[x]+'a';
}
cout<<ss;
return 0;
}