码迷,mamicode.com
首页 > 其他好文 > 详细

[XJOI3497] 字母顺序

时间:2018-07-06 20:27:44      阅读:214      评论:0      收藏:0      [点我收藏+]

标签:using   题目   char   long   freopen   ret   关联   lse   vector   

题目大意:我们熟知的字母表的顺序是从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] 字母顺序

标签:using   题目   char   long   freopen   ret   关联   lse   vector   

原文地址:https://www.cnblogs.com/qixingzhi/p/9275301.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!