Description
一个珍稀书籍的收藏家最近发现了一本用陌生的语言写的一本书,这种语言采用和英语一样的字母。这本书有简单的索引,但在索引中的条目的次序不同于根据英语字母表给出的字典排序的次序。这位收藏家试图通过索引来确定这个古怪的字母表的字符的次序,(即对索引条目组成的序列进行整理),但因为任务冗长而乏味,就放弃了。
请编写程序完成这位收藏家的任务,程序输入一个按特定的序列排序的字符串集合,确定字符的序列是什么。
Input
输入是由大写字母组成的字符串的有序列表,每行一个字符串。每个字符串最多包含20个字符。该列表的结束标志是一个单一字符’#’的一行。并不是所有的字母都被用到,但该列表蕴涵对于被采用的那些字母存在着一个完全的次序。
Output
输出可能存在三种情况:如果不能得到一个完全次序,则输出none;如果次序不唯一,则输出 non-unique;如果能唯一确定,则输出字母的排列次序。
Sample Input 1
XWY
ZX
ZXY
ZXW
YWWX
#
Sample Output 1
XZYW
Hint
字符串数目最多不超过5000个。
建图时只需要比较相邻的两个字串来获得字母大小关系,因为两两相互比较的大小关系可以用相邻比较的结果来得到
#include<cstdio> #include<iostream> #include<queue> #include<cstring> typedef long long ll; using namespace std; const int maxn = 30, maxm = 5005, inf = 0x3f3f3f3f; int fir[maxn], to[maxm], ne[maxm], np; void add(int x, int y) { ne[++np] = fir[x]; fir[x] = np; to[np] = y; } char w[maxm][maxn]; int cnt; void data_in() { char tmp[maxn]; cnt = 0; while(true) { scanf("%s", tmp); if(tmp[0] == '#') break; strcpy(w[++cnt], tmp); } } int n; int rd[maxn]; int mark[maxn], ha[maxn][maxn]; vector<int> topo; int toposort() { int ret = 1; queue<int> Q; for(int i=0; i<26; i++) if(mark[i] && !rd[i]) Q.push(i); while(!Q.empty()) { if(Q.size()>=2) ret = 2; int u = Q.front(); Q.pop(); topo.push_back(u); for(int i=fir[u]; i; i=ne[i]) { int v = to[i]; if(!--rd[v]) Q.push(v); } } if(topo.size() < n) ret = 0; return ret; } void sett() { for(int i=2; i<=cnt; i++) { int j = i-1, k = 0; while(w[i][k] && w[j][k]) { if(w[i][k] != w[j][k]) break; k++; } if(w[i][k] && w[j][k]){ int x = w[i][k] - 'A', y = w[j][k] - 'A'; if(ha[x][y]) continue; ha[x][y] = 1; add(x, y); rd[y]++; mark[x]++; mark[y]++; } } n = 0; for(int i=0; i<26; i++) if(mark[i]) n++; } void solve() { sett(); int ok = toposort(); if(ok == 0) puts("none"); else if(ok == 2) puts("non-unique"); else for(int i = topo.size()-1; i>=0; i--) putchar(topo[i]+'A'); } int main() { data_in(); solve(); return 0; } /* XWY ZX ZXY ZXW YWWX # */