POJ 3691 AC自动机上的dp

题目大意:

给定一些不合理的DNA序列,再给一段较长的dna序列,问最少修改几次可以使序列中不存在任何不合理序列,不能找到修改方法输出-1

这里你修改某一个点的DNA可能会影响后面,我们不能单纯的找匹配数,因为你找到了你也不一定有方法改变它

这里用DP来解决

判断到第i位dna , 之前dp值保存了前面dna所能到达的所有状态:

dp[i][j] 也就是用了前i个dna所到达的状态至少需要修改的值

从所有状态出发,经过AGCT4种情况到达下一个状态,只要下一个状态不为非法状态即可

过程中只要判断你走的AGCT4种情况是否和当前字符相同,相同说明不用做出改变,即+0 , 否则+1,不断进行更新

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <queue>
  4 #include <vector>
  5 #include <iostream>
  6 #include <algorithm>
  7 #include <map>
  8 using namespace std;
  9 #define clr(x) memset(x , 0 , sizeof(x))
 10 #define set(x) memset(x , -1 , sizeof(x))
 11 typedef long long LL ;
 12
 13 const int CHAR_SIZE = 4;
 14 const int MAX_SIZE = 1005;
 15 const int M = 10000 ;
 16 int n,m,p;
 17 int mp[256];
 18
 19 struct AC_Machine{
 20     int ch[MAX_SIZE][CHAR_SIZE] , val[MAX_SIZE] , fail[MAX_SIZE];
 21     int sz;
 22
 23     void init(){
 24         sz = 1;
 25         clr(ch[0]) , clr(val);
 26     }
 27
 28     void insert(char *s){
 29         int n = strlen(s);
 30         int u=0 ;
 31         for(int i=0 ; i<n ; i++){
 32             int c = mp[s[i]];
 33             if(!ch[u][c]){
 34                 clr(ch[sz]);
 35                 val[sz] = 0;
 36                 ch[u][c] = sz++;
 37             }
 38             u = ch[u][c];
 39         }
 40         val[u] = 1;
 41     }
 42
 43     void get_fail(){
 44         queue<int> Q;
 45         fail[0] = 0;
 46         for(int c=0 ; c<CHAR_SIZE ; c++){
 47             int u = ch[0][c];
 48             if(u){Q.push(u);fail[u]=0;}
 49         }
 50         while(!Q.empty()){
 51             int r = Q.front();
 52             Q.pop();
 53             val[r] |= val[fail[r]];
 54             for(int c=0 ; c<CHAR_SIZE ; c++){
 55                 int u = ch[r][c];
 56                 if(!u){ch[r][c] = ch[fail[r]][c]; continue;}
 57                 fail[u] = ch[fail[r]][c];
 58                 Q.push(u);
 59             }
 60         }
 61     }
 62 }ac;
 63
 64 char str[1005];
 65 int f[1005][MAX_SIZE];
 66 int solve()
 67 {
 68     memset(f , 0x3f , sizeof(f));
 69     f[0][0] = 0;
 70     int len = strlen(str) , ret=0x3f3f3f3f;
 71     for(int i=1 ; i<=len ; i++){
 72         int v = mp[str[i-1]];
 73         for(int j=0 ; j<ac.sz ; j++){
 74             for(int k=0 ; k<CHAR_SIZE ; k++){
 75                 if(!ac.val[ac.ch[j][k]]){
 76                     f[i][ac.ch[j][k]] = min(f[i-1][j]+(v==k?0:1) , f[i][ac.ch[j][k]]);
 77                 }
 78             }
 79         }
 80     }
 81     for(int i=0 ; i<ac.sz ; i++){
 82         ret = min(ret , f[len][i]);
 83     }
 84     if(ret == 0x3f3f3f3f) return -1;
 85     else return ret;
 86 }
 87
 88 int main()
 89 {
 90    // freopen("in.txt" , "r" , stdin);
 91    // freopen("out.txt" , "w" , stdout);
 92     mp[‘A‘] = 0 , mp[‘G‘] = 1 , mp[‘C‘] = 2 , mp[‘T‘] = 3;
 93     int cas = 0;
 94     while(scanf("%d" , &n),n){
 95         ac.init();
 96         for(int i=1 ; i<=n ; i++){
 97             scanf("%s" , str);
 98             ac.insert(str);
 99         }
100         ac.get_fail();
101         scanf("%s" , str);
102         printf("Case %d: " , ++cas);
103         printf("%d\n" , solve());
104     }
105     return 0;
106 }
时间: 2024-10-23 13:53:42

POJ 3691 AC自动机上的dp的相关文章

poj--1625Censored!+AC自动机上的dp+大数

题目链接:点击进入 其实看起来是完全可以用矩阵做的,但是因为用到了大数的,导致内存开不下,所以用dp写了.其实dp的过程依旧就是在我们用禁止出现单词构建的trie上走m步的过程.我们定义dp[i][j]表示走过i步以后到达节点j的方案数,则状态转移应该是dp[i][j]=sum(dp[i-1][k]),其中k表示可以走到j的节点,并且不能是病毒节点.但是其实这样代码就不是那么好写了,其实我们可以用节点j主动的去更新它的子节点k,这样转移方程就成了dp[i][next[j][k]]+=dp[i-1

bzoj 1030: [JSOI2007]文本生成器 (ac自动机上的dp)

1030: [JSOI2007]文本生成器 Time Limit: 1 Sec  Memory Limit: 162 MB Submit: 2635  Solved: 1090 [Submit][Status][Discuss] Description JSOI交给队员ZYX一个任务,编制一个称之为"文本生成器"的电脑软件:该软件的使用者是一些低幼人群,他们现在使用的是GW文本生成器v6版.该软件可以随机生成一些文章―――总是生成一篇长度固定且完全随机的文章-- 也就是说,生成的文章中

POJ 3691 (AC自动机+状态压缩DP)

题目链接:  http://poj.org/problem?id=3691 题目大意:给定N的致病DNA片段以及一个最终DNA片段.问最终DNA片段最少修改多少个字符,使得不包含任一致病DNA. 解题思路: 首先说一下AC自动机在本题中的作用. ①字典树部分:负责判断当前0~i个字符组成的串是否包含致病DNA,这部分靠字典树上的cnt标记完成. ②匹配部分:主要依赖于匹配和失配转移关系的计算,这部分非常重要,用来构建不同字符间状态压缩的转移关系(代替反人类的位运算). 这也是必须使用AC自动机而

HNU 13108-Just Another Knapsack Problem (ac自动机上的dp)

题意: 给你一个母串,多个模式串及其价值,求用模式串拼接成母串(不重叠不遗漏),能获得的最大价值. 分析: ac自动机中,在字典树上查找时,用dp,dp[i]拼成母串以i为结尾的子串,获得的最大价值,dp[i]=max(dp[i],dp[i-len]+val[tmp]).,len是模式串的长度,val[tmp]为其价值. #include <cstdio> #include <cstring> #include <cmath> #include <queue>

POJ2778 DNA Sequence AC自动机上dp

网址:https://vjudge.net/problem/POJ-2778 题意: 给出字符集${A,C,G,T}$和一些字符串(长度不超过$10$,且数量不超过$10$个),求长度为$n(n \leq 2e9)$的字符串中不包括上面这些字符串的字符串的数量. 题解: 我们可以先考虑一种方式:设$dp(i,j)$是用了$i$个字符拼出符合题意的长度为$j$的字符串的数量,在本题中$dp(i,j)=\sum _{j' \subseteq j} dp(i-1,j')$,显然时间复杂度是指数级的,不

URAL 1158 AC自动机上的简单DP+大数

题目大意 在一种语言中的字母表中有N(N<=50)个字母,每个单词都由M(M<=50)个字母构成,因此,一共可以形成N^M个单词.但是有P(P<=10)个串是被禁止的,也就是说,任何单词的子串都不能包含这P个串中的任意一个.问按照上述规则,能产生的合法串一共有多少个? 例如:N=3 M=3 P=3 字母表中的三个字符是QWE 被禁止的串为”QQ”,”WEE”,”Q”,则合法的串一共有7个. 这题目相当于通过步数对AC自动机上每一个点的状态进行DP dp[i][j]表示到达i这个点,走了j

hdu 3247 AC自动+状压dp+bfs处理

Resource Archiver Time Limit: 20000/10000 MS (Java/Others)    Memory Limit: 100000/100000 K (Java/Others)Total Submission(s): 2382    Accepted Submission(s): 750 Problem Description Great! Your new software is almost finished! The only thing left to

hdu 3992 AC自动机上的高斯消元求期望

Crazy Typewriter Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 391    Accepted Submission(s): 109 Problem Description There was a crazy typewriter before. When the writer is not very sober, it

UVA 11468(Substring-AC自动机上dp)[Template:AC自动机]

Substring Given a set of pattern strings, and a text, you have to find, if any of the pattern is a substring of the text. If any of the pattern string can be found in text, then print "yes", otherwise "no" (without quotes). But, unfort