HDU 2457 (AC自动机 DP)
2016-06-17 12:30
253 查看
题目链接:点击这里
题意:给定一个DNA串, 至少改变多少字母才能使得所有的模式串都不出现在这个DNA串里.
先给所有的模式串建立AC自动机,然后DNA串就不能走到自动机上的危险节点, 也就是模式串的结尾节点. 假设dp[i][j]表示在字典树上i节点, DNA串长为j的最小改变个数, 转移就是d[i][j]=min{dp[k][j−1]dp[k][j−1]+1buf[k]=buf[i+1],k是文本串i的后继不是模式串结尾buf[k]≠buf[i+1],k不是文本串i的后继且k不是模式串结尾
#include <bits/stdc++.h> using namespace std; #define maxn 1005 #define INF 1111111 int dp[maxn][maxn];//在字典树上i节点 长度为j 最少改变了多少次 int n; char str[maxn]; void change (char *s) { int len = strlen (s); for (int i = 0; i < len; i++) { if (s[i] == 'A') s[i] = 'a'; else if (s[i] == 'C') s[i] = 'b'; else if (s[i] == 'G') s[i] = 'c'; else s[i] = 'd'; } } struct trie { int next[maxn][4], fail[maxn], end[maxn]; int root, cnt; int new_node () { memset (next[cnt], -1, sizeof next[cnt]); end[cnt++] = 0; return cnt-1; } void init () { cnt = 0; root = new_node (); } void insert (char *buf) {//字典树插入一个单词 int len = strlen (buf); int now = root; for (int i = 0; i < len; i++) { int id = buf[i]-'a'; if (next[now][id] == -1) { next[now][id] = new_node (); } now = next[now][id]; } end[now]++; } void build () {//构建fail指针 queue <int> q; fail[root] = root; for (int i = 0; i < 4; i++) { if (next[root][i] == -1) { next[root][i] = root; } else { fail[next[root][i]] = root; q.push (next[root][i]); } } while (!q.empty ()) { int now = q.front (); q.pop (); end[now] += end[fail[now]]; for (int i = 0; i < 4; i++) { if (next[now][i] == -1) { next[now][i] = next[fail[now]][i]; } else { fail[next[now][i]] = next[fail[now]][i]; q.push (next[now][i]); } } } } int query (char *buf) { int len = strlen (buf); for (int i = 0; i < cnt; i++) { for (int j = 0; j <= len; j++) dp[i][j] = INF; } dp[0][0] = 0; for (int j = 0; j < len; j++) { for (int i = 0; i < cnt; i++) { if (end[i]) continue; int id = buf[j]-'a'; int nexti = next[i][id]; if (!end[nexti]) {//可以走到这个点 dp[nexti][j+1] = min (dp[nexti][j+1], dp[i][j]); } for (int x = 0; x < 4; x++) if (x != id) { nexti = next[i][x]; if (!end[nexti]) { dp[nexti][j+1] = min (dp[nexti][j+1], dp[i][j]+1); } } } } int ans = INF; for (int i = 0; i < cnt; i++) ans = min (ans, dp[i][len]); if (ans >= INF) ans = -1; return ans; } }ac; int main () { int kase = 0; while (scanf ("%d", &n) == 1 && n) { ac.init (); for (int i = 1; i <= n; i++) { scanf ("%s", str); change (str); ac.insert (str); } ac.build (); scanf ("%s", str); change (str); printf ("Case %d: %d\n", ++kase, ac.query (str)); } return 0; }
相关文章推荐
- 软件测试之缺陷预防
- Oracle数据库(上)
- 详细的介绍Unity5的AssetBundle
- iOS 字符串处理
- 7、磁盘和文件管理
- transform:rotate在手机上显示有锯齿的解决方案大全
- 实验四 主存空间的分配和回收
- how to fix GIT error: object file is empty?
- O-2-1 赚钱宝安装entware
- Android动画
- Android中的测试小demo
- 6、权限管理
- Oracle基本概念
- What is the best Gantt Chart plugin for Atlassian Jira? - Quora
- UML类图几种关系的总结
- eclipse部署web项目至本地的tomcat但在webapps中找不到
- 全权:从多旋翼角度看新时代下的航空人才需求
- [转]PL/SQL Developer 导入导出csv文件
- 原生实现移动端轮播图 带触摸
- android图片视差滚动效果