首页 > 代码库 > 【AC自动机】【矩阵乘法】poj2778 DNA Sequence

【AC自动机】【矩阵乘法】poj2778 DNA Sequence

http://blog.csdn.net/morgan_xww/article/details/7834801

讲得很好~可以理解自动机的本质,就是一个用来状态转移的东西~对于确定的输入而言,可以从初始状态,按照转移边,转移到确定的终止状态。

而这种转移可以用矩乘加速。

#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
#include<iostream>
using namespace std;
typedef long long ll;
#define MOD 100000ll
typedef vector<ll> vec;
typedef vector<vec> mat;
int N;
mat I,A;
mat operator * (const mat &a,const mat &b)
{
    mat c(N,vec(N));
    for(int i=0;i<N;++i)
      for(int j=0;j<N;++j)
        for(int k=0;k<N;++k)
          c[i][j]=(c[i][j]+a[i][k]*b[k][j]%MOD)%MOD;
    return c;
}
mat Quick_Pow(mat x,int p)
{
    if(!p) return I;
    mat res=Quick_Pow(x,p>>1);
    res=res*res;
    if(p&1) res=res*x;
    return res;
}
queue<int>q;
int child[110][4],fail[110],size=1,sum,ma[1111];
bool word[110];
void Insert(char S[])
{
	int len=strlen(S);
	int now=0;
	for(int i=0;i<len;++i)
	  {
	  	if(!child[now][ma[S[i]]])
	  	  child[now][ma[S[i]]]=size++;
	  	now=child[now][ma[S[i]]];
	  }
	word[now]=1;
}
void build()
{
	fail[0]=-1;
	q.push(0);
	while(!q.empty())
	  {
	  	int U=q.front(); q.pop();
	  	for(int i=0;i<4;++i)
	  	  if(child[U][i])
	  	    {
	  	      int V=fail[U];
	  	      while(V!=-1)
	  	        {
	  	          if(child[V][i])
	  	            {
	  	              fail[child[U][i]]=child[V][i];
	  	              break;
	  	            }
	  	          V=fail[V];
	  	        }
	  	      if(V==-1)
	  	        fail[child[U][i]]=0;
	  	      if(word[fail[child[U][i]]])
	  	        word[child[U][i]]=1;//如果某个单词是该结点所在单词的前缀,那么该结点也应被标记为单词结点 
	  		  q.push(child[U][i]);
	  	    }
	  	  else if(U)
	  	    child[U][i]=child[fail[U]][i];//当然你在dp过程中在Trie上跳也行,但这样就避免了重复计算
			  //由于BFS,其实形成了一个类似链表的结构 
	  }
}
int m,n,ma2[110];
int main()
{
//	freopen("poj2778.in","r",stdin);
	ma[‘A‘]=0; ma[‘G‘]=1; ma[‘C‘]=2; ma[‘T‘]=3;
	char s[13];
	scanf("%d%d",&m,&n);
	for(int i=1;i<=m;++i)
	  {
	  	scanf("%s",s);
	  	Insert(s);
	  }
	build();
	for(int i=0;i<size;++i)
	  if(!word[i])
	    ma2[i]=N++;
	I.assign(N,vec(N));
	for(int i=0;i<N;++i)
	  I[i][i]=1;
	mat A(N,vec(N));
	for(int i=0;i<size;++i)
	  for(int j=0;j<4;++j) if((!word[i]) && (!word[child[i][j]]))
		++A[ma2[i]][ma2[child[i][j]]];
//	for(int i=0;i<N;++i)
//	  {
//	  	for(int j=0;j<N;++j)
//	  	  printf("%d ",A[i][j]);
//	  	puts("");
//	  }
	A=Quick_Pow(A,n);
//	for(int i=0;i<N;++i)
//	  {
//	  	for(int j=0;j<N;++j)
//	  	  printf("%d ",A[i][j]);
//	  	puts("");
//	  }
	ll ans=0;
	for(int i=0;i<N;++i)
	  ans=(ans+A[0][i])%MOD;
	cout<<ans<<endl;
	return 0;
}

【AC自动机】【矩阵乘法】poj2778 DNA Sequence