zoukankan      html  css  js  c++  java
  • [BZOJ1195]:[HNOI2006]最短母串(AC自动机+BFS)

    题目传送门


    题目描述

    给定n个字符串(S1,S2,…,Sn),要求找到一个最短的字符串T,使得这n个字符串(S1,S2,…,Sn)都是T的子串。


    输入格式

    第一行是一个正整数n,表示给定的字符串的个数。
    以下的n行,每行有一个全由大写字母组成的字符串。每个字符串的长度不超过50。

    输出格式

    只有一行,为找到的最短的字符串T。在保证最短的前提下,
    如果有多个字符串都满足要求,那么必须输出按字典序排列的第一个。

    样例

    样例输入:
    2
    ABCD
    BCDABC
    样例输出:
    ABCDABC

    数据范围与提示

    对于全部数据,1≤n≤12,1≤|Si|≤50

    题解

    一看是多模式串,首先应该想到是AC自动机。

    如果还不会AC自动机,可以转到这篇博客,个人感觉还是写的挺清楚的:AC自动机讲解+[HDU2222]:Keywords Search(AC自动机)

    那么我们考虑怎么去处理。

    看到n的取值范围之后,我们可以考虑状态压缩。
    然后,要求串最短,且字典序最小,那么可以考虑BFS从跟节点开始,每个状态A->Z爆搜,那么这样的话就可以保证当前搜到的串。
    统计答案时从最后一个点往前找即可。

    代码时刻

    #include<bits/stdc++.h>
    using namespace std;
    int trie[5000][5000],cnt=1,ed[5000],nxt[5000];
    char s[50];
    int que[5000],que1[10000000],que2[10000000],que3[10000000],que4[10000000];
    //que用于求Fail指针
    //que1-4用于BFS,que1用于存储答案,que2用于存储上一个点在队列中的位置,que3用与存储当前点的编号,que4用于存储状态
    bool vis[5000][5000];
    int tot;
    int n;
    int ans[5000];
    void insert(char *str,int id)//依然建树
    {
    	int len=strlen(str);
    	int p=1;
    	for(int i=0;i<len;i++)
    	{
    		int ch=str[i]-'A';
    		if(!trie[p][ch])trie[p][ch]=++cnt;
    		p=trie[p][ch];
    	}
    	ed[p]|=1<<(id-1);
    }
    void build()//找Fail指针
    {
    	for(int i=0;i<26;i++)trie[0][i]=1;
    	que[1]=1;
    	int head=1,tail=1;
    	while(head<=tail)
    	{
    		for(int i=0;i<26;i++)
    		{
    			if(!trie[que[head]][i])trie[que[head]][i]=trie[nxt[que[head]]][i];
    			else
    			{
    				que[++tail]=trie[que[head]][i];
    				nxt[trie[que[head]][i]]=trie[nxt[que[head]]][i];
    				ed[trie[que[head]][i]]|=ed[trie[nxt[que[head]]][i]];
    			}
    		}
    		head++;
    	}
    }
    void ask()//BFS
    {
    	int head=1,tail=1;
    	int end=(1<<n)-1;
    	que3[1]=1;
    	while(head<=tail)
    	{
    		if(que4[head]==end)
    		{
    			while(head>1)
    			{
    				ans[++tot]=que1[head];
    				head=que2[head];
    			}
    			while(tot--)printf("%c",ans[tot+1]+'A');
    			return;
    		}
    		for(int i=0;i<26;i++)
    			if(!vis[trie[que3[head]][i]][que4[head]|ed[trie[que3[head]][i]]])//用vis存储当前状态有没有被访问过
    			{
    				que1[++tail]=i;//添加这个点
    				que2[tail]=head;//存储上一个点
    				que3[tail]=trie[que3[head]][i];//存储当前点的编号
    				que4[tail]=que4[head]|ed[trie[que3[head]][i]];//存储状态
    				vis[trie[que3[head]][i]][que4[head]|ed[trie[que3[head]][i]]]=1;//表示当前状态已经被访问过
    			}
    		head++;
    	}
    }
    int main()
    {
    	scanf("%d",&n);
    	for(int i=1;i<=n;i++)
    	{
    		scanf("%s",s);
    		insert(s,i);
    	}
    	build();
    	ask();
    	return 0;
    }
    

    rp++

  • 相关阅读:
    单一index.php实现PHP任意层级文件夹遍历(原创自Zjmainstay)
    php读取文件内容至字符串中,同时去除换行、空行、行首行尾空格(原创自Zjmainstay)
    php获取页面并切割页面div内容
    jQuery单击双击实现链接的提取、插入与删除
    PHP 利用AJAX获取网页并输出(原创自Zjmainstay)
    php 数组首字符过滤功能
    点击图片添加文件在Chrome中使用的兼容问题
    php读取txt文件组成SQL并插入数据库(原创自Zjmainstay)
    为博客园添加标签云动画
    jQuery动态增删改查表格信息,可左键/右键提示(原创自Zjmainstay)
  • 原文地址:https://www.cnblogs.com/wzc521/p/11090270.html
Copyright © 2011-2022 走看看