病毒(virus) 题解 - 拓扑排序

题目

有一天,小y突然发现自己的计算机感染了一种病毒!还好,小y发现这种病毒很弱,只是会把文档中的所有字母替换成其它字母,但并不改变顺序,也不会增加和删除字母。
现在怎么恢复原来的文档呢!小y很聪明,他在其他没有感染病毒的机器上,生成了一个由若干单词构成的字典,字典中的单词是按照字母顺序排列的,他把这个文件拷贝到自己的机器里,故意让它感染上病毒,他想利用这个字典文件原来的有序性,找到病毒替换字母的规律,再用来恢复其它文档。
现在你的任务是:告诉你被病毒感染了的字典,要你恢复一个字母串。

输入格式
第一行为整数K(≤50000),表示字典中的单词个数。
以下K行,是被病毒感染了的字典,每行一个单词。
最后一行是需要你恢复的一串字母。
所有字母均为小写。

输出格式
输出仅一行,为恢复后的一串字母。当然也有可能出现字典不完整、甚至字典是错的情况,这时请输出一个0。

样例

样例输入
6
cebdbac
cac
ecd
dca
aba
bac
cedab
样例输出
abcde


思路


这一道题最先看的时候,发现这什么鬼题?
之后我看了题解后,我终于知道怎么套进 用拓扑排序了


我们可以使用 s t r i n g string string来存储输入的字符串。
我们可以比较相邻两个词第一个不相同的字母,后面就不能比较了,因为我们无法确定它们的顺序。
因为拥有字符串之间的大小关系,所以可以快快乐乐 建图了。之后就可以使用拓扑排序,把病毒的字母大小的排列方式拿出来,同时再与真实字符串相联系起来(可以用 M a p Map Map),最后求出正确字符串。

在这当中,一定要注意 0 0 0的情况:
1、若其中没有字母入度为零,即代表有环,那么就无解(想一想,一个最小的却要求比最开始的要大,肯定不可能)
2、若最后字符串中映射不完整,那么就代表所给词典不完整


这一题,主要突破点在于字符串字符的有序性,所以可以做出来。

代码

#include
#include
#include
#include
#include
using namespace std;
const int M=10005;
int in[M],qwq[M];
map<char,char> ma;
vector<int> G[M];
int main(){
	int n;
	scanf("%d",&n);
	string s[M],need;
	for(int i=1;i<=n;i++){
		cin>>s[i];
	}
	cin>>need;
	for(int i=2;i<=n;i++){
		int len=min(s[i].length(),s[i-1].length());
		for(int j=0;j<len;j++){
			if(s[i][j]!=s[i-1][j]){
				int x=s[i-1][j]-'a'+1,y=s[i][j]-'a'+1;
				G[x].push_back(y);
				in[y]++;
				qwq[y]++,qwq[x]++;
				break;
			} 
		}
	}
	int tot=0;
	for(int i=1;i<=n;i++){
		if(qwq[i]) tot++; 
	}
	for(int i=1;i<=tot;i++){
		int j=1;
		while(j<27&&(in[j]||!qwq[j])) j++;
		if(j>26){
			printf("0\n");
			return 0;
		}
		ma[j+'a'-1]='a'+i-1;
		in[j]=-1;
		int siz=G[j].size();
		for(int k=0;k<siz;k++){
			int id=G[j][k];
			in[id]--;
		}
	}
	string ans;
	for(int i=0;i<need.length();i++){
		if(!ma[need[i]]){
			printf("0\n");
			return 0;
		}
		ans[i]=ma[need[i]];
	}
	for(int i=0;i<need.length();i++){
		cout<<ans[i];
	}
	return 0;
}

你可能感兴趣的:(图论,拓扑排序,字符串)