[XJOI3497] 字母顺序
Posted qixingzhi
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[XJOI3497] 字母顺序相关的知识,希望对你有一定的参考价值。
题目大意:我们熟知的字母表的顺序是从a到z,现在假设你可以重新安排字母表的顺序,给你一些单词,问你能否安排出一种顺序,使得每个单词从左往右读过去都是非递减的顺序。如果可以输出Possible
乍一看无从下手,因为这和图论看上去毫无关联。但实际上总结下来,能否安排出一种顺序其实就是通过某种方法来找出矛盾。
既然题目已经给出了若干个单词了,那么这些单词本身就是已知条件。因为如果想找出一种满足条件的字母表顺序,那么每个单词之间的关系应该要符合。例如,单词simple,就必须满足但单词表的顺序中s s >= i >= m >= p >= l >= e,而在单词topcoder中就必须满足t >= o >= p >= c >= o >= d >= e >= r。既然存在这种复杂的关系,为什么不选择连边呢?若已知u>=v,则可以从u到v连一条有向边,表示u>=v。如果想要符合条件,必然不能出现环。因为有环就意味着发生了矛盾。于是问题就被我们转化成了有向图判断是否有环。但那是不是意味着在单词simple中,s要向i,m,p,l,e全都连一条边了吗?那复杂度不是n^2过不了了?其实不然,并不需要麻烦的把s直接连那么多次,s只需要连到它的直接后属i就可以了,因为这样s与它之后的所有字母都是间接连通的,也就传达了>=的关系。这样建图的复杂度就是O(n)了。
那么很简单,从每一个点开始广搜,判断是否能回到自己。注意vis数组每次要清零。
另外,特别需要注意的是,单词aa是满足条件的,因为题目要求的是非递减。所以如果前后相同就不需要连边了。(被这个点坑惨了……)
/*By QiXingzhi*/ #include <cstdio> #include <queue> #include <cstring> #include <algorithm> #include <string> #include <cstdlib> #include <iostream> #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 = 715827882; 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; } int n,m,ans,len,_cur,flg; string s; bool vis[260],exist[N]; vector <int> G[260]; queue <int> q; inline void AddEdge(int u, int v){ if(u==v)return; G[u].push_back(v); } void 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){ printf("Impossible"); exit(0); } } 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); } } } int main(){ // freopen(".in","r",stdin); while(cin >> s){ int len = s.size(); for(int i = 0; i < len-1; ++i){ exist[s[i]-‘a‘] = 1; AddEdge(s[i]-‘a‘,s[i+1]-‘a‘); } exist[s[len-1]-‘a‘] = 1; } for(int i = 0; i <= 25; ++i){ memset(vis,0,sizeof(vis)); if(exist[i]){ _cur = i; flg = -1; BFS(_cur); } } printf("Possible"); return 0; }
以上是关于[XJOI3497] 字母顺序的主要内容,如果未能解决你的问题,请参考以下文章
csharp 在Swashbuckle Swagger中,此片段允许按字母顺序显示操作。
片段(Java) | 机试题+算法思路+考点+代码解析 2023
2021-12-24:划分字母区间。 字符串 S 由小写字母组成。我们要把这个字符串划分为尽可能多的片段,同一字母最多出现在一个片段中。返回一个表示每个字符串片段的长度的列表。 力扣763。某大厂面试