[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

带字母的字母列表 - 可点击

XJOI NOIP模拟题1

2021-12-24:划分字母区间。 字符串 S 由小写字母组成。我们要把这个字符串划分为尽可能多的片段,同一字母最多出现在一个片段中。返回一个表示每个字符串片段的长度的列表。 力扣763。某大厂面试

XJOI contest 1592