Fox And Names:原题链接
题意:
题目会给出字符串的个数n经过排序后的字符串,但注意,该字符串排序处于被打乱状态,即不同于正常的字符串排序(a,b,c,d,e......x,y,z),现在请求出打乱后的字典序。
注:答案不唯一,只要符合题意即可。
做题思路:
有题意可知,题目需要查找先后,关于先后,优先考虑拓扑排序。
而本题用拓扑排序的难点在于如何建图,代码如下:
int minn=min(s1.size(),s2.size());
//后面需要j的位置,判断两个字符串是否一致
int j=0;
for (;j<minn;j++){
//查找两个字符串中第一个不同的字符
if (s1[j]!=s2[j]) {
in[s2[j]-'a']++;
g[s1[j]-'a'].push_back(s2[j]-'a');
break;
}
}
为什么可以这样写,首先我们需要先了解字符串怎么排序:
假设我们有两个字符串s1,s2。s1="aa",s2="z"。而字符串的大小为s1<s2。
原因是字符串大小排序只取两个字符串中第一个不同的字符,所以,我们可以对比两个字符串中长度较小的一个,遍历两个字符串,并将不同的两个字符作为原拓扑排序的from,to,找到后停止。
显然这样做还有一个问题,如果出现两个字符串相等,但是s1>sxz2的情况怎么办?那就特判呗。
//倘若j执行到最后且s1的长度>s2的长度
//说明字符串排序有问题 ,存在环
if (j==minn && s1.size()>s2.size())return cout <<"Impossible\n",0;
//使s1继承s2
在有解决建图问题后,接下来就可以用拓扑排序来判断字典序了,核心代码如下:
bool topu(){
queue<int>q;
//从26个字母中查找出入度为0的起点
for (int i=0;i<26;i++)
{
if (in[i]==0)q.push(i);
}
//经典拓扑排序
while(!q.empty()) {
int now=q.front();
q.pop();
tp.push_back(now);
for (auto i:g[now]) {
if (--in[i]==0)q.push(i);
}
}
//判断字典序是否为26
//否,代表字符序有问题 ,有环存在
return tp.size()==26;
}
处理完以上两点,只要添加上输入和输出,代码就完成了。这里是AC代码:
#include <bits/stdc++.h>
using namespace std;
const int N=105,inf=INT_MAX, M=1e3+10;
int n;
string s1,s2;
int in[N];
vector<int>tp;
vector<int>g[N];
bool topu(){
queue<int>q;
//从26个字母中查找出入度为0的起点
for (int i=0;i<26;i++)
{
if (in[i]==0)q.push(i);
}
//经典拓扑排序
while(!q.empty()) {
int now=q.front();
q.pop();
tp.push_back(now);
for (auto i:g[now]) {
if (--in[i]==0)q.push(i);
}
}
//判断字典序是否为26
//否,代表字符序有问题 ,有环存在
return tp.size()==26;
}
int main(){
cin >>n;
//为方便输入,采用s1继承s2的形式进行执行
cin >>s1;
for (int i=2;i<=n;i++)
{
cin >>s2;
//因为要遍历字符串,所以选择字符串中最小的长度
int minn=min(s1.size(),s2.size());
//后面需要j的位置,判断两个字符串是否一致
int j=0;
for (;j<minn;j++){
//查找两个字符串中第一个不同的字符
if (s1[j]!=s2[j]) {
in[s2[j]-'a']++;
g[s1[j]-'a'].push_back(s2[j]-'a');
break;
}
}
//倘若j执行到最后且s1的长度>s2的长度
//说明字符串排序有问题
if (j==minn && s1.size()>s2.size())return cout <<"Impossible\n",0;
//使s1继承s2
s1=s2;
}
if (topu())
{
//将tp数组转换会字符
for (int i=0;i<26;i++)cout <<char(tp[i]+'a');
cout <<"\n";
}
else cout <<"Impossible\n";
return 0;