HDU 2457 DNA repair(AC自动机+DP)题解
题意:给你几个模式串,问你主串最少改几个字符能够使主串不包含模式串
思路:从昨天中午开始研究,研究到现在终于看懂了。既然是多模匹配,我们是要用到AC自动机的。我们把主串放到AC自动机上跑,并保证不出现模式串,这里对AC自动机的创建有所改动,我们需要修改不存在但是符合要求的节点,如果某节点的某一子节点不存在,我们就把这个子节点指向他父辈节点存在的该节点(比如k->next[1]不存在,k->fail->next[1]存在,我们就把他改为k->next[1] = k->fail->next[1]),因为只是在AC自动机上跑,我们只关心会不会匹配到模式串。这里要当心,如果一个节点的失配指向的是模式串尾,那么这个节点也就是模式串尾。我们用dp[i][j]去储存当前匹配到主串第i位,跑到AC自动机第j个状态的最小修改,状态转移方程dp[i + 1][j-next] = min(dp[i][j->next],dp[i][j]+str[i]!=k),每次我们都从上一个状态j开始搜索满足要求的下一个状态j->next。
参考:
[Pku 3691 1625] 字符串(四) {自动机应用}
代码:
#include<cstdio>
#include<vector>
#include<set>
#include<map>
#include<queue>
#include<cstring>
#include<string>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#define ll long long
const int maxn = 1000+5;
const int maxm = 100000+5;
const int MOD = 1e7;
const int INF = 0x3f3f3f3f;
const int kind = 4;
const char baset = 0;
using namespace std;
struct Trie{
Trie *next[kind];
Trie *fail;
int flag;
int id;
};
Trie *root,point[maxn];
queue<Trie*> Q;
int head,tail,idx;
int ID(char ch){
if(ch == 'A') return 0;
else if(ch == 'C') return 1;
else if(ch == 'T') return 2;
return 3;
}
Trie* NewNode(){
Trie *temp = &point[idx];
memset(temp ->next,NULL,sizeof(temp ->next));
temp ->flag = 0;
temp ->id = idx++;
temp ->fail = NULL;
return temp;
}
void Insert(char *s){
Trie *p = root;
for(int i = 0;s[i];i++){
int x = ID(s[i]);
if(p ->next[x] == NULL){
p ->next[x] = NewNode();
}
p = p ->next[x];
}
p ->flag = 1;
}
void del(Trie *p){
if(p == NULL) return;
for(int i = 0;i < kind;i++){
if(p ->next[i])
del(p ->next[i]);
}
delete p;
}
void buildFail(){
while(!Q.empty()) Q.pop();
Q.push(root);
Trie *p,*temp;
while(!Q.empty()){
temp = Q.front();
Q.pop();
for(int i = 0;i < kind;i++){
if(temp ->next[i]){
if(temp == root){
temp ->next[i] ->fail = root;
}
else{
p = temp ->fail;
while(p){
if(p ->next[i]){
temp ->next[i] ->fail = p ->next[i];
break;
}
p = p ->fail;
}
if(p == NULL) temp ->next[i] ->fail = root;
}
if(temp ->next[i] ->fail ->flag)
temp ->next[i] ->flag = 1;
//这里要注意,如果一个节点的失配指向的是模式串尾
//那么这个节点也就是模式串尾
Q.push(temp ->next[i]);
}
else if(temp == root)
temp ->next[i] = root;
//root指向root,因为不存在这个子节点,没有限制
else
temp ->next[i] = temp ->fail ->next[i];
//指向长辈节点存在的这个子节点
}
}
}
int dp[maxn][maxn << 1]; //主串匹配到第i个,在AC自动机上走到第j个节点
int solve(char *ch){
int len = strlen(ch);
for(int i = 0;i <= len;i++)
for(int j = 0;j <= idx;j++)
dp[i][j] = INF;
dp[0][0] = 0;
for(int i = 1;i <= len;i++){
for(int j = 0;j < idx;j++){ //从这个状态j开始走,dp下一个状态
if(point[j].flag) continue; //这个状态包含模式串
if(dp[i - 1][j] == INF) continue;
for(int k = 0;k < 4;k++){
int r = point[j].next[k] ->id; //下一个点
if(point[r].flag) continue; //下一个点包含模式串
dp[i][r] = min(dp[i][r],dp[i - 1][j] + (ID(ch[i - 1]) != k));
}
}
}
int ans = INF;
for(int i = 0;i < idx;i++){
ans = min(ans,dp[len][i]);
}
if(ans == INF) return -1;
else return ans;
}
char ch[1005];
int main(){
int n,m,x,Case = 1;
while(scanf("%d",&n) != EOF && n){
idx = 0;
root = NewNode();
for(int i = 0;i < n;i++){
scanf("%s",ch);
Insert(ch);
}
buildFail();
scanf("%s",ch);
printf("Case %d: %d\n",Case++,solve(ch));
}
return 0;
}
HDU 2457 DNA repair(AC自动机+DP)题解的更多相关文章
- HDU 2457 DNA repair (AC自动机+DP)
题意:给N个串,一个大串,要求在最小的改变代价下,得到一个不含上述n个串的大串. 思路:dp,f[i][j]代表大串中第i位,AC自动机上第j位的最小代价. #include<algorithm ...
- POJ 3691 & HDU 2457 DNA repair (AC自己主动机,DP)
http://poj.org/problem?id=3691 http://acm.hdu.edu.cn/showproblem.php?pid=2457 DNA repair Time Limit: ...
- HDU 2457/POJ 3691 DNA repair AC自动机+DP
DNA repair Problem Description Biologists finally invent techniques of repairing DNA that contains ...
- HDU2457 DNA repair —— AC自动机 + DP
题目链接:https://vjudge.net/problem/HDU-2457 DNA repair Time Limit: 5000/2000 MS (Java/Others) Memory ...
- [hdu2457]DNA repair(AC自动机+dp)
题意:给出一些不合法的模式DNA串,给出一个原串,问最少需要修改多少个字符,使得原串中不包含非法串. 解题关键:多模式串匹配->AC自动机,求最优值->dp,注意在AC自动机上dp的套路. ...
- POJ 3691 DNA repair(AC自动机+DP)
题目链接 能AC还是很开心的...此题没有POJ2778那么难,那个题还需要矩阵乘法,两个题有点相似的. 做题之前,把2778代码重新看了一下,回忆一下当时做题的思路,回忆AC自动机是干嘛的... 状 ...
- POJ3691 DNA repair(AC自动机 DP)
给定N个长度不超过20的模式串,再给定一个长度为M的目标串S,求在目标串S上最少改变多少字符,可以使得它不包含任何的模式串 建立Trie图,求得每个节点是否是不可被包含的串,然后进行DP dp[i][ ...
- Hdu 2457 DNA repair (ac自己主动机+dp)
题目大意: 改动文本串的上的字符,使之不出现上面出现的串.问最少改动多少个. 思路分析: dp[i][j]表示如今 i 个字符改变成了字典树上的 j 节点. 然后顺着自己主动机一直转移方程. 注意合法 ...
- hdu 4117 GRE Words AC自动机DP
题目:给出n个串,问最多能够选出多少个串,使得前面串是后面串的子串(按照输入顺序) 分析: 其实这题是这题SPOJ 7758. Growing Strings AC自动机DP的进阶版本,主题思想差不多 ...
随机推荐
- 关于线上js报错问题的思考
1.有没有可能对线上报错进行实时监控,只要线上报错出现就会以邮件的形式发出来. 2.有没有可能将每个模块和开发者联系起来,只要报错就直接报给开发者
- EUI组件之TextInput
输入文本,被废弃的组件,可以用EditableText代替
- 百度地图API开发----手机地图做导航功能
第一种方式:手机网页点击打开直接进百度地图APP <a href="baidumap://map/direction?mode=[transit:公交,driving:驾车]& ...
- Linux系统下 MongoDB安装搭建
1.下载linux的mongodb 2.在目录usr/local下创建文件夹mongodb,把安装包解压到该文件夹中 # mkdir mongodb # tar -zxvf mongodb-3.4.2 ...
- java8新增的日期时间包
Clock clock=Clock.systemUTC(); System.out.println("当前时刻为:"+clock.instant()); System.out.pr ...
- 关于#ifndef以及#ifndef WIN32
一般用法是这样的: 这里可以定义如下: #define XXXXX #ifdef XXXXX 这里做一些操作,这些操作只有在XXXX已经被define的情况下才会执行到.一般还可能有else,如 #e ...
- Servlet + JSP 时代
Spring,Django,Rails,Express这些框架技术的出现都是为了解决什么问题,现在这些框架都应用在哪些方面? - 知乎 https://www.zhihu.com/question/2 ...
- Python开发【模块】:Concurrent
concurrent 模块 回顾: 对于python来说,作为解释型语言,Python的解释器必须做到既安全又高效.我们都知道多线程编程会遇到的问题,解释器要留意的是避免在不同的线程操作内部共享的数据 ...
- 控制HttpContext为null
直接new一个 HttpContextBase _HttpContext= new HttpContextWrapper(System.Web.HttpContext.Current);
- PID参数调整的口诀
PID参数调整的口诀:参数整定找最佳,从小到大顺序查先是比例后积分,最后再把微分加曲线振荡很频繁,比例度盘要放大曲线漂浮绕大湾,比例度盘往小扳曲线偏离回复慢,积分时间往下降曲线波动周期长,积分时间再加 ...