POJ 3691 (AC自动机+状态压缩DP)
题目链接: http://poj.org/problem?id=3691
题目大意:给定N个致病DNA片段以及一个最终DNA片段。问最终DNA片段最少修改多少个字符,使得不包含任一致病DNA。
解题思路:
首先说一下AC自动机在本题中的作用。
①字典树部分:负责判断当前0~i个字符组成的串是否包含致病DNA,这部分靠字典树上的cnt标记完成。
②匹配部分:主要依赖于匹配和失配转移关系的计算,这部分非常重要,用来构建不同字符间状态压缩的转移关系(代替反人类的位运算)。
这也是必须使用AC自动机而不单单是字典树的原因。
本题的状态压缩DP思路:
因为是求最少修改的字符。我们把最终DNA片段从第一个字符开始,先枚举字典树中所有字符,作为pre状态。
然后枚举四种修改方案,作为now状态,如果该方案与当前字符的值不同,则次数+1。
如果是致病DNA则跳过。
通过一个Trie的数组池(pool)确定(0<k<4)四种修改方案之后的转移点t的位置,t=pos->next[k]-pool
这样dp[now][t]=min(dp[now][t],dp[pre][j]+0 or 1)
本来的转移方程应该是dp[i][t]=min(dp[i][t],dp[i-1][j]+0 or 1) ,这里感谢zcwwzdjn大神提供的一个滚动数组的优化,也就是now和pre的使用。
同时他的动态AC自动机的变相静态写法也很独特, 主要是pool数组用来确定字符在字典树中标号,弥补了动态写法的不足。
#include "cstdio"
#include "string"
#include "queue"
#include "cstring"
#include "iostream"
using namespace std;
#define maxn 55*25
#define inf 0x3f3f3f3f
struct Trie
{
Trie *next[],*fail;
int cnt;
}pool[maxn],*root,*sz;
int dp[][maxn],now,pre;
Trie *newnode()
{
Trie *ret=sz++;
memset(ret->next,,sizeof(ret->next));
ret->fail=;
ret->cnt=;
return ret;
}
int idx(char c)
{
if(c=='A') return ;
if(c=='G') return ;
if(c=='C') return ;
if(c=='T') return ;
}
void Insert(string str)
{
Trie *pos=root;
for(int i=;i<str.size();i++)
{
int c=idx(str[i]);
if(!pos->next[c]) pos->next[c]=newnode();
pos=pos->next[c];
}
pos->cnt++;
}
void getfail()
{
queue<Trie *> Q;
for(int c=;c<;c++)
{
if(root->next[c])
{
root->next[c]->fail=root;
Q.push(root->next[c]);
}
else root->next[c]=root;
}
while(!Q.empty())
{
Trie *x=Q.front();Q.pop();
for(int c=;c<;c++)
{
if(x->next[c])
{
x->next[c]->fail=x->fail->next[c];
x->next[c]->cnt+=x->fail->next[c]->cnt;
Q.push(x->next[c]);
}
else x->next[c]=x->fail->next[c];
}
}
}
void init()
{
sz=pool; //reset
root=newnode();
}
int main()
{
//freopen("in.txt","r",stdin);
ios::sync_with_stdio(false);
int n,no=;
string tt;
while(cin>>n&&n)
{
init();
for(int i=;i<=n;i++)
{
cin>>tt;
Insert(tt);
}
getfail();
cin>>tt;
int cnt=sz-pool;
now=,pre=;
memset(dp,0x3f,sizeof(dp));
dp[now][]=;
for(int i=;i<tt.size();i++)
{
now^=,pre^=;
memset(dp[now], 0x3f, sizeof(dp[now]));
for(int j=;j<cnt;j++)
{
if(dp[pre][j]<inf)
{
Trie *pos=pool+j;
for(int k=;k<;k++)
{
if(pos->next[k]->cnt) continue;
int t=pos->next[k]-pool;
int add=idx(tt[i])==k?:;
dp[now][t]=min(dp[now][t],dp[pre][j]+add);
}
}
}
}
int ans=inf;
for(int i=;i<cnt;i++) ans=min(ans,dp[now][i]);
if(ans==inf) printf("Case %d: -1\n",++no);
else printf("Case %d: %d\n",++no,ans);
}
}
13518359 | neopenx | 3691 | Accepted | 232K | 63MS | C++ | 2696B | 2014-10-10 22:10:31 |
POJ 3691 (AC自动机+状态压缩DP)的更多相关文章
- HDU 4511 (AC自动机+状态压缩DP)
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=4511 题目大意:从1走到N,中间可以选择性经过某些点,比如1->N,或1->2-> ...
- hdu 4057(ac自动机+状态压缩dp)
题意:容易理解... 分析:题目中给的模式串的个数最多为10个,于是想到用状态压缩dp来做,它的状态范围为1-2^9,所以最大为2^10-1,那我们可以用:dp[i][j][k]表示长度为i,在tri ...
- bzoj1195 神奇的ac自动机+状态压缩dp
/* 难的不是ac自动机,是状态压缩dp 之前做了一两题类似题目,感觉理解的还不够透彻 */ #include<iostream> #include<cstdio> #incl ...
- HDU 4057 Rescue the Rabbit ( AC自动机 + 状态压缩DP )
模板来自notonlysuccess. 模式串只有10个,并且重复出现的分值不累加,因此很容易想到状态压缩. 将模式串加入AC自动机,最多有10*100个状态. dp[i][j][k]:串长为i,在T ...
- 计蒜客-蒜场抽奖(AC自动机+状态压缩DP)
题解:题意不再说了,题目很清楚的. 思路:因为N<=10,所以考虑状态压缩 AC自动机中 val[1<<i]: 表示第i个字符串.AC自动机中fail指针是指当前后缀在其他串里面所能 ...
- HDU 4758 Walk Through Squares( AC自动机 + 状态压缩DP )
题意:给你两个串A,B, 问一个串长为M+N且包含A和B且恰好包含M个R的字符串有多少种组合方式,所有字符串中均只含有字符L和R. dp[i][j][k][S]表示串长为i,有j个R,在自动机中的状态 ...
- hdu 2825(ac自动机+状态压缩dp)
题意:容易理解... 分析:在做这道题之前我做了hdu 4057,都是同一种类型的题,因为题中给的模式串的个数最多只能为10个,所以我们就很容易想到用状态压缩来做,但是开始的时候我的代码超时了dp时我 ...
- POJ 1321 棋盘问题(状态压缩DP)
不总结的话, 同一个地方会 WA 到死 思路: 状态压缩 DP. 1. s 表示压缩状态, 若第 i 列放了棋子, 那么该列置 1, 否则该列置 0. 假如 s = 3(0x011) 那么表示棋盘的第 ...
- POJ 3254 Corn Fields(状态压缩DP)
Corn Fields Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 4739 Accepted: 2506 Descr ...
随机推荐
- PHP 上传文件和读取文件崎岖路
今天php上传文件和读取文件没有搞出来,全靠后来大神来帮忙,总结一下:主要涉及到一下几个方面,在ubuntu下mkdir文件夹的时候要注意权限问题,一般情况下php是以一个较低的权限去执行的,所以如果 ...
- [BZOJ1061][Noi2008]志愿者招募
[BZOJ1061][Noi2008]志愿者招募 试题描述 申奥成功后,布布经过不懈努力,终于成为奥组委下属公司人力资源部门的主管.布布刚上任就遇到了一个难 题:为即将启动的奥运新项目招募一批短期志愿 ...
- ZeroMQ(java)中监控Socket
基本上ZeroMQ(java)中基本的代码都算是过了一遍了吧,不过觉得它在日志这一块貌似基本没有做什么工作,也就是我们通过日志来知道ZeroMQ都发生了什么事情.. 而且由于ZeroMQ中将连接的建立 ...
- HDOJ 1106
#include<iostream> #include<algorithm> #include<string.h> #include<stdlib.h> ...
- 【Django】Django 如何支持 分组查询、统计?
代码: from django.db.models import Sum alarm_sum_group_items = models.FILE_PROTECT_ALARM.objects.filte ...
- 【Hadoop】HIVE 小结概览
一.HIVE概览小结 二.HIVE安装 Hive只在一个节点上安装即可 .上传tar包 .解压 tar -zxvf hive-.tar.gz -C /cloud/ .配置mysql metastore ...
- 【转】基于LDA的Topic Model变形
转载自wentingtu 基于LDA的Topic Model变形最近几年来,随着LDA的产生和发展,涌现出了一批搞Topic Model的牛人.我主要关注了下面这位大牛和他的学生:David M. B ...
- linux下创建库函数
来源: 在Linux下如何使用自己的库函数-riverok-ChinaUnix博客 http://blog.chinaunix.net/uid-21393885-id-88128.html 构建Lin ...
- delphi 换行操作 Word
delphi 换行操作 我将我的商用<旅行社管理系统>的 发团通知 部分奉献给您,望对您有所帮助. procedure TFrmMain.N327Click(Sender: TObject ...
- 2.saltstack笔记之目标,模块,返回写入数据库
作者:刘耀 QQ:22102107 一.目标(targeting Minions) 1.匹配Minions Id 匹配所有 (*) [root@node1 salt]# salt '*' test.p ...