集训考试题(CF510C Fox And Names的简化版)
题目描述
给定n个由小写字母组成的字符串,请你求出一个字母表顺序,使得这n个字符串是按照字典序升序排列的,数据保证存在合法的字母表顺序。
如果存在多个解,输出字典序最小的那个。
输入格式
第一行一个整数n.接下来n行,每行一个字符串。
输出格式
一行,一个a到z各出现一次的字符串,表示字母表顺序 。
样例读入:
10
petr
egor
endagorion
feferivan
ilovetanyaromanova
kostka
dmitriyh
maratsnowbear
bredorjaguarturnik
cgyforever
样例输出:
aghjlnopefikdmbcqrstuvwxyz
先水一下在考场上的骗分思路:
可以发现的是,非常有意思的,把所有的字符串的首字母提取出来,以样例为例,也就是:
peefikdmbc
去重后就是:
pefikdmbc
然后发现它在样例输出里存在,接着又发现,把其他的,没有在这个小串里出现的字幕按照正常的字母表顺序接在这个小串两边,就凑出了样例,
前半段自然是好凑,而后半段,我们则直接输出这个小串的首字母,也就是p,在字母表后没有出现的字母堆在后面,就凑出了样例:
前半段自然是:aghjlno
后半段自然是:qrstuvwxyz
然后我们就得到了样例输出:aghjlnopefikdmbcqrstuvwxyz
然后可能是存在某种正确性,但是一般不是字典序最小,但是我依旧骗到了大量的部分分
接着我们讲正解思路:
我们想要使得字符串的顺序有一个优先级,就意味着最基本的,他们的首字母有一个优先级
然后要是上下两个字符串的前半部分相等,那么就可以确定这之后的头一个字母的优先级
然后我们假设在一张图上优先级低的指向了优先级高的,也就是建立了一个拓扑序
我们根据拓扑序确定一个顺序。
优先级低的指向优先级高的,也就是将优先级高的的字母的入读加一
先将所有入度为0的存入答案数组,再按照拓扑序记录答案,最后输出即可
因为题目保证了一定合法,所以我们可以不考虑不合法的情况,但是如果一定有不合法的情况,我们判断也很简单
1.若两个字符串,一个字符串能够在另一个字符串中找到,且较长的字符串在短的字符串的上面,这是显然不合法的
2.若最后拓扑结束后,答案数组里存的字母不到26个,显然是不合法的
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxn = 1100; 4 int n, top = 0; 5 char s[maxn][maxn], ans[maxn]; 6 int in[maxn], lin[maxn][maxn];//lin表示两个字符串连接一条边bulabulabula 7 bool flag = 1; 8 9 inline int read() { 10 int x = 0, y = 1; 11 char ch = getchar(); 12 while(!isdigit(ch)) { 13 if(ch == '-') y = -1; 14 ch = getchar(); 15 } 16 while(isdigit(ch)) { 17 x = (x << 1) + (x << 3) + ch - '0'; 18 ch = getchar(); 19 } 20 return x * y; 21 } 22 23 queue<int> q; 24 inline bool topsort_solve() { 25 for(int i = 0; i < 26; ++i) 26 if(!in[i]) { 27 q.push(i); 28 ans[++top] = char(i + 'a'); 29 } 30 while(!q.empty()) { 31 int k = q.front(); q.pop(); 32 for(int i = 0; i < 26; ++i) 33 if(lin[k][i]) { 34 in[i]--; 35 if(!in[i]) { 36 ans[++top] =char(i + 'a'); 37 q.push(i); 38 } 39 } 40 } 41 if(top < 26) return 0; 42 else return 1; 43 } 44 45 int main() { 46 memset(in, 0, sizeof(in)); 47 memset(lin, 0, sizeof(lin)); 48 n = read(); 49 for(int i = 0; i < n; ++i) 50 cin >> s[i]; 51 for(int i = 0; i < n - 1; ++i) { 52 int len1 = strlen(s[i]); 53 int len2 = strlen(s[i + 1]); 54 int j = 0; 55 while(j < len1 && j < len2 && s[i][j] == s[i + 1][j]) j++; 56 if(j < len1 && j < len2) { 57 if(!lin[s[i][j] - 'a'][s[i + 1][j] - 'a']) {//建立top关系//建图 58 lin[s[i][j] - 'a'][s[i + 1][j] - 'a'] = 1; 59 in[s[i + 1][j] - 'a']++; 60 } 61 } 62 else if(len1 > len2) flag = 0; 63 } 64 if(!flag) cout << "Impossible" << '\n'; 65 else if(flag) { 66 flag = topsort_solve(); 67 if(!flag) cout << "Impossible" << '\n'; 68 else { 69 for(int i = 1; i <= top; ++i) 70 cout << ans[i]; 71 cout << '\n'; 72 } 73 } 74 return 0; 75 }