POJ 2778 DNA Sequence AC自动机+DP+矩阵二分加速

本文探讨了利用AC自动机与动态规划解决字符串问题的方法,详细介绍了构造AC自动机的过程,以及如何通过自动机进行动态规划来计算长度为n的不包括特定字符串的串的个数。

题目链接http://poj.org/problem?id=2778

http://vjudge.net/contest/view.action?cid=51731#problem/E


1.题意

告诉你m个字符串,每个字符串长度不超过10,求长度为n的不包括这m个字符串的串的个数。

2.题解

(1)前提要会构造ac自动机;

(2)构造自动机的目的是做DP,DP_i_j表示长度为i且末尾状态为j的串可以由多少种长度为i-1的状态得到 ,那个DP_i_j=西格玛(DP_i-1_k(0<=k<=top)),用g[i][j]表示长度为0的串到长度为n的串到从状态i转移状态j的路径有多少种(路径有多少种就说明在长度为n的串末尾加一个字符后,不产生病毒串,可以有多少种添加字符的方法)。用自动机构造且判断DP_i-1_k(k为所有状态)到DP_i_j这样的转移是否存在,如果k状态是end态(说明走到了病毒上面了),则转移不存在;如果k状态是 !end 态,且k状态的fail态全都是!end态(在构造自动机的时候,每bfs一个状态时就可以每次判断一次他的fail转移是不是end态,如果是end态,就说明他的后缀有病毒,不管他到底是不是end态,也都要改变成end态),如果next[k][c]有边(不管是fail转移到j状态,还是接受后转移到j状态都算)可以到j状态,则转移存在,那就用矩阵把对于的g[k][j]加一。

(3)初次求得g[][]矩阵时,它表示从字符串长度0到字符串长度1,状态i到状态j之间的转移可以有几种,只要求出g[][]的n次方,就可以知道从字符串长度0到字符串长度n,状态i到状态j之间的转移可以有几种;


code:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
/**
5 4
AAA
ATA
T
TA
TAA
初始矩阵
2 1 0 0 0 0 0 0 0
2 0 1 0 0 0 0 0 0
2 0 0 0 0 0 0 0 0
2 0 0 0 0 0 0 0 0
2 0 0 0 0 0 0 0 0
2 0 0 0 0 0 0 0 0
2 0 0 0 0 0 0 0 0
2 0 0 0 0 0 0 0 0
2 0 0 0 0 0 0 0 0
处理后的矩阵
52 18 6 0 0 0 0 0 0
48 16 6 0 0 0 0 0 0
36 12 4 0 0 0 0 0 0
36 12 4 0 0 0 0 0 0
36 12 4 0 0 0 0 0 0
36 12 4 0 0 0 0 0 0
36 12 4 0 0 0 0 0 0
36 12 4 0 0 0 0 0 0
36 12 4 0 0 0 0 0 0

76
**/
#define Clear(x) memset(x,0,sizeof x)
typedef long long LL;
const int MAXN=108,MAX=4,MOD=100000;
int sz;
struct Mat{
    int m[MAXN][MAXN];
    Mat(){Clear(m);}
    Mat(int x){
        Clear(m);
        for(int i=0;i<sz;i++)
            m[i][i]=x;
    }
};
Mat operator*(Mat a,Mat b){
    Mat ret;
    int i,j,k;
    for(i=0;i<sz;i++)
        for(j=0;j<sz;j++){
            if(a.m[i][j]==0) continue;
            for(k=0;k<sz;k++){
                int tmp=((LL)a.m[i][j]*b.m[j][k])%MOD;
                ret.m[i][k]=(ret.m[i][k]+tmp)%MOD;
            }
        }
    return ret;
}
Mat Pow(Mat a,int b){
    Mat ret(1);
    while(b){
        if(b&1)ret=ret*a;
        a=a*a;
        b>>=1;
    }
    return ret;
}
Mat dp;

int ch[MAXN][MAX],f[MAXN],top;
bool end[MAXN];
int idx(char ch){
    switch(ch){
        case 'A':return 0;
        case 'C':return 1;
        case 'G':return 2;
    }
    return 3;//T
}
void init(){
    top=0;
    Clear(end);
    Clear(f);Clear(ch);
}
int NewNode(){return ++top;}
void insert(char *s,int num){
    int x=0,n=strlen(s);
    for(int i=0;i<n;i++){
        int c=idx(s[i]);
        if(!ch[x][c]) ch[x][c]=NewNode();
        x=ch[x][c];
    }
    end[x]=true;
}
void getFail(){
    queue<int>Q;
    for(int c=0;c<MAX;c++){
        int &u=ch[0][c];
        if(u)Q.push(u);
    }
    while(!Q.empty()){
        int r=Q.front();Q.pop();
        if(end[f[r]])//!!!
            end[r]=true;
        for(int c=0;c<MAX;c++){
            int u=ch[r][c];
            int v=f[r];
            if(!u){ch[r][c]=ch[v][c];continue;}
            Q.push(u);
            while(v && !ch[v][c]) v=f[v];
            f[u]=ch[v][c];
        }
    }
}
void getDP(){
    Clear(dp.m);
    for(int i=0;i<=top;i++){
        for(int j=0;j<MAX;j++){
            if(!end[ch[i][j]]) dp.m[i][ch[i][j]]++;
        }
    }
}
int main()
{
//    freopen("data.in","r",stdin);
    int n,m;
    char P[20];
    while(scanf("%d%d",&n,&m)==2){
        init();
        for(int i=1;i<=n;i++){
            scanf("%s",P);
            insert(P,i);
        }
        getFail();
        sz=top+1;
        getDP();
        dp=Pow(dp,m);
        int ans=0;
        for(int i=0;i<sz;i++){
            ans+=dp.m[0][i];
            ans%=MOD;
        }
        printf("%d\n",ans);
    }
    return 0;
}


六自由度机械臂ANN人工神经网络设计:正向逆向运动学求解、正向动力学控制、拉格朗日-欧拉法推导逆向动力学方程(Matlab代码实现)内容概要:本文档围绕六自由度机械臂的ANN人工神经网络设计展开,详细介绍了正向与逆向运动学求解、正向动力学控制以及基于拉格朗日-欧拉法推导逆向动力学方程的理论与Matlab代码实现过程。文档还涵盖了PINN物理信息神经网络在微分方程求解、主动噪声控制、天线分析、电动汽车调度、储能优化等多个工程与科研领域的应用案例,并提供了丰富的Matlab/Simulink仿真资源和技术支持方向,体现了其在多学科交叉仿真与优化中的综合性价值。; 适合人群:具备一定Matlab编程基础,从事机器人控制、自动化、智能制造、电力系统或相关工程领域研究的科研人员、研究生及工程师。; 使用场景及目标:①掌握六自由度机械臂的运动学与动力学建模方法;②学习人工神经网络在复杂非线性系统控制中的应用;③借助Matlab实现动力学方程推导与仿真验证;④拓展至路径规划、优化调度、信号处理等相关课题的研究与复现。; 阅读建议:建议按目录顺序系统学习,重点关注机械臂建模与神经网络控制部分的代码实现,结合提供的网盘资源进行实践操作,并参考文中列举的优化算法与仿真方法拓展自身研究思路。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值