出处: Codeforces
主要算法:判环+拓扑
难度:4.2
思路分析:
要是把这道题联系到图上就很容易想了。
如何建图?由于最后要求名字满足字典序,所以不妨以字母为节点,然后按照题意的顺序从小的到大的连边。建图了又什么用?如果图存在环,那么也就意味着矛盾了——因为这比自己小的节点比自己大。因此是否存在一个合法的字典序的判断依据就是建的图是否存在环。
第二步,如何输出任意一个方案?这很简单,由于有可能有的字母根本没有参与建图,所以这些字母就不需要管了。对于在图里的字母,入度为0的点就是已知的应当最小的点——所以我们进行一次拓扑排序来得到序列。最后和其它字母拼合起来就好了。
代码注意点:
注意有两个相同前缀的字符串时,如果前面的那个字符串比后面的还要长,那么一定不满足,直接输出impossible就好了。因为无论字典序如何,都不可能满足前面的字典序比后面的小。
Code
/** This Program is written by QiXingZhi **/ #include <cstdio> #include <queue> #include <iostream> #include <string> #include <cstring> #include <cstdlib> #include <algorithm> #define r read() #define Max(a,b) (((a)>(b)) ? (a) : (b)) #define Min(a,b) (((a)<(b)) ? (a) : (b)) using namespace std; typedef long long ll; const int N = 1010; const int INF = 1061109567; inline int read(){ int x = 0; int w = 1; register int c = getchar(); while(c ^ '-' && (c < '0' || c > '9')) c = getchar(); if(c == '-') w = -1, c = getchar(); while(c >= '0' && c <= '9') x = (x << 3) +(x << 1) + c - '0', c = getchar(); return x * w; } string s[N]; queue <int> q; vector <int> G[3000]; bool exist[N],vis[N],b[N],hh[N]; int rd[N],Q[N],ans_topo[N]; int n,len1,len2,flg,_cur,t,topo_num; inline void AddEdge(int u, int v){ exist[u] = 1; exist[v] = 1; G[u].push_back(v); ++rd[v]; } inline void ThrowOut(){ printf("Impossible"); exit(0); } inline bool BFS(int x){ while(!q.empty()) q.pop(); q.push(x); int cur,sz,to; while(!q.empty()){ cur = q.front(); q.pop(); if(cur == _cur){ if(flg == -1){ ++flg; } else if(flg == 0){ return 1; } } if(vis[cur]) continue; vis[cur] = 1; sz = G[cur].size(); for(int i = 0; i < sz; ++i){ to = G[cur][i]; q.push(to); } } return 0; } inline bool Check_Circle(){ for(int i = 'a'; i <= 'z'; ++i){ memset(vis,0,sizeof(vis)); if(exist[i]){ _cur = i; flg = -1; if(BFS(_cur)) return 1; } } return 0; } int main(){ // freopen(".in","r",stdin); cin >> n; for(int i = 1; i <= n; ++i){ cin >> s[i]; } for(int i = 2; i <= n; ++i){ len1 = s[i-1].size(); len2 = s[i].size(); flg = 0; for(int j = 0; j < len2; ++j){ if(j >= len1){ flg = 1; break; } if(s[i-1][j] != s[i][j]){ flg = 1; AddEdge(s[i-1][j],s[i][j]); break; } } if(flg == 0 && len1 > len2){ ThrowOut(); } } if(Check_Circle() == 1){ ThrowOut(); } int flg=0,sz; for(;;){ flg = 0, t = 0; for(int i = 'a'; i <= 'z'; ++i){ if(rd[i] == 0 && !b[i] && exist[i]){ flg = 1; b[i] = 1; Q[++t] = i; } } if(!flg) break; for(int i = 1; i <= t; ++i){ int cur = Q[i]; ans_topo[++topo_num] = cur; hh[cur] = 1; sz = G[cur].size(); for(int j = 0; j < sz; ++j){ --rd[G[cur][j]]; } } } for(int i = 1; i <= topo_num; ++i){ printf("%c",ans_topo[i]); } for(int i = 'a'; i <= 'z'; ++i){ if(!hh[i]){ printf("%c",i); } } return 0; }