AC自动机+DP(POJ2778&&POJ3691)

本文分享了使用AC自动机结合动态规划解决两类问题的方法。一类是构建转移矩阵并利用矩阵快速幂优化DP求解模式匹配问题;另一类是通过AC自动机辅助DP求最小编辑距离。代码详细展示了POJ2778和POJ3691两道题目的解题思路。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

闲来无事AC自动机+DP撸两发QAQ

都是傻X题放代码就好了QAQ

POJ2778:AC自动机构建转移矩阵,矩阵快速幂优化dp

#include<queue>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#define LL long long
using namespace std;
const int maxn=10010;
const int mod=100000;
int n,m;
char str[2100];

struct AC_automation{
	int next[maxn][4];
	int end[maxn],fail[maxn];
	int l,root;
	LL a[101][101],b[101][101];
	int newnode(){
        for (int i=0;i<26;++i) next[l][i]=-1;
        end[l]=fail[l]=0; return l++;
    }
    void init(){
        l=0; root=newnode();
    }
	int idx(char c){
		if (c=='A') return 0;
		else if (c=='C') return 1;
		else if (c=='G') return 2;
		else return 3;
	}
	void ins(char buf[]){
        int now=root,l=strlen(buf);
        for (int i=0;i<l;++i){
            int x=idx(buf[i]);
            if (next[now][x]==-1)
                next[now][x]=newnode();
            now=next[now][x];
        }end[now]=1;
    }
	void build(){
        queue<int>q; fail[root]=root;
        for (int i=0;i<4;++i)
            if (next[root][i]!=-1){
                q.push(next[root][i]);
                fail[next[root][i]]=root;
            }else next[root][i]=root;
        while (!q.empty()){
            int now=q.front(); q.pop();
            for (int i=0;i<4;++i)
                if (next[now][i]!=-1){
                    q.push(next[now][i]);
                    fail[next[now][i]]=next[fail[now]][i];
                    if (end[fail[next[now][i]]]) end[next[now][i]]=1;
                }else next[now][i]=next[fail[now]][i];
        }
    }
	void Init_Matrix(){
		for(int i=0;i<l;++i)
		    for (int j=0;j<l;++j)
		        a[i][j]=b[i][j]=0;
		for (int i=0;i<l;++i)
		    for (int j=0;j<4;++j)
		        if (!end[next[i][j]]&&!end[i])
		            a[i][next[i][j]]++;
		b[0][0]=1;
	}
	void mul(LL a[101][101],LL b[101][101],LL c[101][101]){
		LL tmp[101][101];
		for (int i=0;i<l;++i)
		    for (int j=0;j<l;++j){
				tmp[i][j]=0;
		        for (int k=0;k<l;++k)
		            tmp[i][j]=(tmp[i][j]+a[i][k]*b[k][j])%mod;
			}
		for (int i=0;i<l;++i)
		    for (int j=0;j<l;++j)
		        c[i][j]=tmp[i][j];
	}
	void Matrix_power(){
		while (n){
			if (n&1) mul(b,a,b);
			mul(a,a,a); n>>=1;
		}
		LL ans=0;
		for (int i=0;i<l;++i)
		    ans=(ans+b[0][i])%mod;
		printf("%lld",ans);
	}
}Ac;

int main(){
	Ac.init();
	scanf("%d%d",&m,&n);
	for (int i=1;i<=m;++i){
		scanf("%s",str);
		Ac.ins(str);
	}	
	Ac.build();
	Ac.Init_Matrix();
	Ac.Matrix_power();
}

POJ3691:dp[i][j]表示匹配到长度为i且正在j节点的最少修改次数

#include<queue>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#define LL long long
using namespace std;
const int maxn=1010;
const int mod=100000;
int n,m;
char str[2100];

struct AC_automation{
	int next[maxn][4];
	int end[maxn],fail[maxn];
	int l,root,dp[maxn][maxn*2];
	int newnode(){
        for (int i=0;i<26;++i) next[l][i]=-1;
        end[l]=fail[l]=0; return l++;
    }
    void init(){
        l=0; root=newnode();
    }
	int idx(char c){
  		if (c=='A') return 0;
		else if (c=='C') return 1;
		else if (c=='G') return 2;
		else return 3;
	}
	void ins(char buf[]){
        int now=root,l=strlen(buf);
        for (int i=0;i<l;++i){
            int x=idx(buf[i]);
            if (next[now][x]==-1)
                next[now][x]=newnode();
            now=next[now][x];
        }end[now]=1;
    }
	void build(){
        queue<int>q; fail[root]=root;
        for (int i=0;i<4;++i)
            if (next[root][i]!=-1){
                q.push(next[root][i]);
                fail[next[root][i]]=root;
            }else next[root][i]=root;
        while (!q.empty()){
            int now=q.front(); q.pop();
            for (int i=0;i<4;++i)
                if (next[now][i]!=-1){
                    q.push(next[now][i]);
                    fail[next[now][i]]=next[fail[now]][i];
                    if (end[fail[next[now][i]]]) end[next[now][i]]=1;
                }else next[now][i]=next[fail[now]][i];
        }
    }
    void DP(int Case,char s[]){
		memset(dp,127/3,sizeof(dp));
		int HHH=dp[0][0];
		dp[0][0]=0; int len=strlen(s);
		for (int i=1;i<=len;++i)
		    for (int j=0;j<l;++j){
				if (dp[i-1][j]==HHH) continue;
				int now=idx(s[i-1]);
		        for (int k=0;k<4;++k)
		            if (!end[next[j][k]])
		                dp[i][next[j][k]]=min(dp[i][next[j][k]],dp[i-1][j]+(k!=now));
			}
		int ans=HHH;
		for (int i=0;i<l;++i)
		    if (!end[i]) ans=min(ans,dp[len][i]);
		if (ans==HHH) ans=-1;
		printf("Case %d: %d\n",Case,ans);
    }
}Ac;

int main(){
	int Case=0;
	while (scanf("%d",&n)!=EOF){
		if (!n) break;
		Case++;
		Ac.init();
		scanf("%d",&n);
		for (int i=1;i<=n;++i){
			scanf("%s",str);
			Ac.ins(str);
		}
		Ac.build();
		scanf("%s",str);
		Ac.DP(Case,str);
	}
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值