510C Fox And Names(拓扑排序)

题目传送门


给n个字符串,问是否存在字母序列,使得这n个字符串是按照该字典序呈递减排列。


将各个字母看做一个点,根据输入的字符串来确定大小关系,先后输入的两个字符串s[i]与s[i+1],设其第j个字母不同,则此时字母s[i][j]与s[i+1][j]的大小关系可以确定,由字母s[i][j]到s[i+1][j]连一条有向边来表示前者>后者,同时后者入度+1。

注意如果s[i+1]是s[i]的前缀,且s[i+1]长度小于s[i],则显然不可能构造出字母序列。直接输出Impossible。

否则进行拓扑排序,如果最终得到的字母少于26个,则说明有环存在,即存在矛盾,无解。否则依次输出字母序列即可。


#include<bits/stdc++.h>
using namespace std;
char ans[30];
bool edge[30][30];
int deg[30];
char s[101][105];
bool solve()
{
    queue<int> Q;
    int t=0,i;
    for(i=0;i<26;++i)
    {
        if(!deg[i])
        {
            Q.push(i);
            ans[t++]=i+'a';
        }
    }
    while(!Q.empty())
    {
        int p=Q.front();
        Q.pop();
        for(i=0;i<26;++i)
        {
            if(edge[p][i])
            {
                --deg[i];
                if(deg[i]==0)
                {
                    Q.push(i);
                    ans[t++]=i+'a';
                }
                edge[p][i]=0;
            }
        }
    }
    if(t==26) return 1;
    return 0;
}
int main()
{
    int i,j,n,m;
    bool Flag=1;
    cin>>n;
    for(i=1;i<=n;++i)
        scanf("%s",s[i]);
    memset(edge,0,sizeof(edge));
    memset(deg,0,sizeof(deg));
    for(i=1;i<n;++i)
    {
        int l1=strlen(s[i]),l2=strlen(s[i+1]);
        bool flag=0;
        for(j=0;j<l1&&j<l2;++j)
        {
            if(s[i][j]!=s[i+1][j])
            {
                flag=1;
                if(!edge[s[i][j]-'a'][s[i+1][j]-'a'])
                {
                    edge[s[i][j]-'a'][s[i+1][j]-'a']=1;
                    ++deg[s[i+1][j]-'a'];
                }
                break;
            }
        }
        if(!flag&&l2<l1) {Flag=0;break;}
    }
    if(!Flag) puts("Impossible");
    else if(solve()) puts(ans);
    else puts("Impossible");
    return 0;
}



你可能感兴趣的:(510C Fox And Names(拓扑排序))