zoukankan      html  css  js  c++  java
  • BZOJ_3012_[Usaco2012 Dec]First!

    zz:https://blog.csdn.net/diaopang1934/article/details/102276403?depth_1-utm_source=distribute.pc_relevant.none-task&utm_source=distribute.pc_relevant.none-task

    题意: 给定n个总长不超过m的互不相同的字符串,现在你可以任意指定字符之间的大小关系。问有多少个串可能成为字典序最小的串,并输出这些串。n <= 30,000 , m <= 300,000 分析: 首先不考虑大小关系,如果一个串是另一个串的前缀,那么另一个串一定不能成为字典序最小的串,我们可以用trie树很好的解决。 考虑前缀相同的情况,这个串在前缀后的字符应该和含有相同前缀的串在前缀后的字符有明确的大小关系,根据这个大小关系连边,我们用拓扑排序判断是否矛盾。 以上都满足则可以成为字典序最小的串。

    #include <stdio.h>
    #include <string.h>
    #include <algorithm>
    #include <queue>
    using namespace std;
    #define N 30050
    struct A
    {
        int son[30],end;
    }t[N*10];
    int n,tot,head[30],to[N],nxt[N],c[30],cnt=1,ans[30010];
    char s[30010][310];
    void add(int u,int v)
    {
        to[++cnt]=v;
        nxt[cnt]=head[u];
        head[u]=cnt;
        c[v]++; //v的入度加1 
    }
    void insert(int x)
    {
        int p=1;
        int len=strlen(s[x]+1);
        for(int i=1;i<=len;i++)
        {
            int id=s[x][i]-'a'+1; //字符转成数字 
            if(!t[p].son[id])
    		    t[p].son[id]=++cnt;
            p=t[p].son[id];
        }
        t[p].end=1;
    }
    bool search(int x)
    {
        int p=1;
        int len=strlen(s[x]+1);
        for(int i=1;i<=len;i++)
        {
            if(t[p].end)
    		   return 0;
            int id=s[x][i]-'a'+1; //字符转成数字 
            for(int j=1;j<=26;j++)
            {
                if(j!=id&&t[p].son[j])
                {
                    add(id,j);//建一条从id到j的边,id是父亲点,j是其下面的子结点
                }
            }
            p=t[p].son[id];
        }
        return 1;
    }
    bool topsort()
    {
        queue <int> q;
        for(int i=1;i<=26;i++)
    	    if(c[i]==0) //加进入度为0的点 
    		    q.push(i);
        while(!q.empty())
        {
            int x=q.front();
    		q.pop();
            for(int i=head[x];i;i=nxt[i])
            {
                c[to[i]]--;
                if(c[to[i]]==0)
    			   q.push(to[i]);
            }
        }
        for(int i=1;i<=26;i++)
    	   if(c[i])  //如果还存在入度不为0的点,则无法topsort 
    	       return 0;
        return 1;
    }
    int main()
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
        {
            scanf("%s",s[i]+1);
            insert(i);
        }
        for(int i=1;i<=n;i++)
        {
            memset(head,0,sizeof(head));
            memset(c,0,sizeof(c));
    		cnt=0;
            if(!search(i))
    		    continue;
            if(!topsort())
    		    continue;
            ans[++tot]=i;
        }
        printf("%d
    ",tot);
        for(int i=1;i<=tot;i++)
        {
            printf("%s
    ",s[ans[i]]+1);
        }
    }
    
  • 相关阅读:
    IP分类:A,B,C,D,E五类
    Makefile之“=”、":="、“+=”、“?=”
    Makefile之字符串函数
    Makefile之嵌套执行make
    vi中使用“/”查找字符
    Makefile学习之显示命令与出错命令
    【转】Unity中写GLSL(一)—— 简单的diffuse color
    关于编译GITHUB上的工程
    认识了一个新的手机游戏剖析工具- SnapDragon Profiler
    U3D资料收藏
  • 原文地址:https://www.cnblogs.com/cutemush/p/12521190.html
Copyright © 2011-2022 走看看