[字典树][拓扑排序]第一!

题目描述

Bessie一直在研究字符串。她发现,通过改变字母表的顺序,她可以按改变后的字母表来排列字符串(字典序大小排列)。

例如,Bessie发现,对于字符串串“omm”,“moo”,“mom”和“ommnom”,她可以使用标准字母表使“mom”排在第一个(即字典序最小),她也可以使用字母表“abcdefghijklonmpqrstuvwxyz”使得“omm”排在第一个。然而,Bessie想不出任何方法(改变字母表顺序)使得“moo”或“ommnom”排在第一个。

接下来让我们通过重新排列字母表的顺序来计算输入中有哪些字符串可以排在第一个(即字典序最小),从而帮助Bessie。

要计算字符串X和字符串Y按照重新排列过的字母表顺序来排列的顺序,先找到它们第一个不同的字母X[i]与Y[i],按重排后的字母表顺序比较,若X[i]比Y[i]先,则X的字典序比Y小,即X排在Y前;若没有不同的字母,则比较X与Y长度,若X比Y短,则X的字典序比Y小,即X排在Y前。

输入格式

第1行:一个数字N(1 <= N <= 30,000),Bessie正在研究的字符串的数量。

第2~N+1行:每行包含一个非空字符串。所有字符串包含的字符总数不会超过300,000。 输入中的所有字符都是小写字母,即a~z。 输入不包含重复的字符串。

输出格式

第1行:一个数字K,表示按重排后的字母表顺序排列的字符串有多少可以排在第一个数量。

第2~K+1行:第i+1行包含第i个按重排后的字母表顺序排列后可以排在第一个的字符串。字符串应该按照它们在输入中的顺序来输出。

输入输出样例

输入样例

4
omm
moo
mom
ommnom
输出样例
2
omm
mom

说明

样例即是题目描述中的例子,只有“omm”和“mom”在各自特定的字典序下可以被排列在第一个。

分析

首先容易想到当前串包含某个串的话,那么肯定这个串不成立。
然后字符优先,等等,优先?怎么很像拓扑排序?
于是想到相同前缀的两个字母连边拓扑排序看看能不能跑完(即会不会形成环【冲突】)
相同前缀什么的肯定选择字典树啊(才不会KMP呢)

#include <iostream>
#include <cstdio>
#include <cstring>
#include <memory.h>
#include <queue>
#define rep(i,a,b) for (i=a;i<=b;i++)
using namespace std;
int root=0,cnt;
int f[300001][26];
bool b[300001];
bool map[26][26];
int rd[26];
string c[30001];
int n;
void inse(string a)
{
    int r=root,x,i;
    for (i=0;a[i];i++)
    {
        x=a[i]-'a';
        if (!f[r][x]) f[r][x]=++cnt;
        r=f[r][x];
    }
    b[r]=1;
}

void init()
{
    int i,j;
    string a;
    scanf("%d",&n);
    rep(i,1,n)
    {
        cin>>a;
        c[i]=a;
        inse(a);
    }
}
bool searchandget(int j)
{
    string q=c[j];
    int i,k,r=root,x;
    memset(map,0,sizeof(map));
    memset(rd,0,sizeof(rd));
    for (i=0;q[i];i++)
    {
        x=q[i]-'a';
        if (b[r]) return 0;
        rep(k,0,25)
        if (x!=k&&f[r][k]&&!map[x][k])
        {
            map[x][k]=1;
            rd[k]++;
        }
        r=f[r][x];
    }
    return 1;
}
bool top()
{
    queue<int> q;
    int i,x;
    while (!q.empty()) q.pop();
    rep(i,0,25)
    if (!rd[i]) q.push(i);
    while (!q.empty())
    {
        x=q.front();q.pop();
        rep(i,0,25)
        if (map[x][i]&&rd[i])
        {
            rd[i]--;
            if (!rd[i]) q.push(i);
        }
    }
    rep(i,0,25)
    if (rd[i]) return 0;
    return 1;
}
void print()
{
    int i,k=0;
    bool b[30001];
    rep(i,1,n)
    b[i]=0;
    rep(i,1,n)
    if (searchandget(i)&&top())
    {
        k++;
        b[i]=1;
    }
    printf("%d\n",k);
    rep(i,1,n)
    if (b[i])
    cout<<c[i]<<endl;
}
int main()
{
    init();
    print();
}

猜你喜欢

转载自blog.csdn.net/ssl_qyh0ice/article/details/80082002
今日推荐