zoukankan      html  css  js  c++  java
  • 【bzoj1195】[HNOI2006]最短母串 AC自动机+状态压缩+BFS最短路

    原文地址:http://www.cnblogs.com/GXZlegend/p/6825226.html


    题目描述

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

    输入

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

    输出

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

    样例输入

    2
    ABCD
    BCDABC

    样例输出

    ABCDABC


    题解

    AC自动机+BFS

    先求出fail数组和Trie图,同时标记每个位置是哪些字符串的结尾,用二进制储存。

    要求包含所有串的最小长度,需要记录当前包含哪些串,需要状压。

    当到达字符串结尾时,更改状态。

    所以Trie图可以看成一个分层图,所求为0,1到(1<<n)-1,i的最短路。

    由于每条路径代表一个字符,所以边权为1,可以使用BFS求最短路得解。

    #include <cstdio>
    #include <cstring>
    char str[60] , ch[610] , ans[610];
    int tot = 1 , next[610][26] , fail[610] , val[610] , qx[1500010] , qy[1500010] , l , r , dis[610][4096] , fromp[610][4096];
    void build()
    {
    	int x , i;
    	for(i = 0 ; i < 26 ; i ++ ) next[0][i] = 1;
    	l = r = 1 , qx[1] = 1;
    	while(l <= r)
    	{
    		x = qx[l ++ ];
    		for(i = 0 ; i < 26 ; i ++ )
    		{
    			if(next[x][i])
    				fail[next[x][i]] = next[fail[x]][i] , val[next[x][i]] |= val[fail[next[x][i]]] , qx[++r] = next[x][i];
    			else next[x][i] = next[fail[x]][i];
    		}
    	}
    }
    int main()
    {
    	int n , l , i , j , x , y;
    	scanf("%d" , &n);
    	for(i = 1 ; i <= n ; i ++ )
    	{
    		scanf("%s" , str + 1) , l = strlen(str + 1) , x = 1;
    		for(j = 1 ; j <= l ; j ++ )
    		{
    			if(!next[x][str[j] - 'A']) next[x][str[j] - 'A'] = ++tot;
    			x = next[x][str[j] - 'A'] , ch[x] = str[j];
    		}
    		val[x] |= 1 << (i - 1);
    	}
    	build();
    	memset(dis , -1 , sizeof(dis));
    	l = r = 1 , qx[1] = 1 , qy[1] = 0 , dis[1][0] = 0;
    	while(l <= r)
    	{
    		x = qx[l] , y = qy[l];
    		for(i = 0 ; i < 26 ; i ++ )
    		{
    			int tx = next[x][i] , ty = y | val[tx];
    			if(dis[tx][ty] == -1)
    			{
    				dis[tx][ty] = dis[x][y] + 1 , fromp[tx][ty] = l;
    				if(ty == (1 << n) - 1)
    				{
    					int px = tx , py = ty , tmp;
    					for(i = dis[tx][ty] ; i ; i -- )
    						ans[i] = ch[px] , tmp = fromp[px][py] , px = qx[tmp] , py = qy[tmp];
    					printf("%s
    " , ans + 1);
    					return 0;
    				}
    				qx[++r] = tx , qy[r] = ty;
    			}
    		}
    		l ++ ;
    	}
    	return 0;
    }

     

  • 相关阅读:
    调用AsyncTask的excute方法不能立即执行程序的原因分析及改善方案
    辅助
    目录检索
    高斯消元法
    树套树
    珂朵莉树
    卢卡斯定理
    中国剩余定理
    数论基础
    网络流基础
  • 原文地址:https://www.cnblogs.com/GXZlegend/p/6825226.html
Copyright © 2011-2022 走看看