HDU 3341 (AC自动机 DP)
2016-06-17 16:31
483 查看
题目链接:点击这里
题意:给出n个DNA模式串, 和一个文本串, 调整文本串字符的顺序使得所有模式串出现的次数和最多.
因为四种字符出现的次数都有限, 可以用类似于进制的做法记录字符出现的状态, 如果四个字符的总数有a, b, c, d, 当前状态出现的次数是x, y, z, k, 那么状态就记录为x×(b+1)×(c+1)×(d+1)+y×(c+1)×(d+1)+z×(d+1)+k×1
然后建立AC自动机在上面转移状态就好了.
#include <bits/stdc++.h> using namespace std; #define maxn 505 #define INF 1111111 int n; char str[55][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 dp[maxn][11*11*11*11];//在字典树i节点 四种字母出现状态 int bit[5]; int query (int a, int b, int c, int d, char *buf) { memset (dp, -1, sizeof dp); dp[0][0] = 0; bit[0] = (b+1)*(c+1)*(d+1), bit[1] = (c+1)*(d+1), bit[2] = (d+1), bit[3] = 1; for (int x = 0; x <= a; x++) { for (int y = 0; y <= b; y++) { for (int z = 0; z <= c; z++) { for (int k = 0; k <= d; k++) { int p = x*bit[0]+y*bit[1]+z*bit[2]+k*bit[3]; for (int i = 0; i < cnt; i++) { if (dp[i][p] == -1) continue; for (int id = 0; id < 4; id++) { if (id == 0 && x == a) continue; if (id == 1 && y == b) continue; if (id == 2 && z == c) continue; if (id == 3 && k == d) continue; int nexti = next[i][id]; int nextp = p + bit[id]; dp[nexti][nextp] = max (dp[nexti][nextp], dp[i][p] + end[nexti]); } } } } } } int state = a*bit[0] + b*bit[1] + c*bit[2] + d*bit[3]; int ans = 0; for (int i = 0; i < cnt; i++) ans = max (ans, dp[i][state]); return ans; } }ac; char buf[maxn]; int main () { int kase = 0; while (scanf ("%d", &n) == 1 && n) { ac.init (); for (int i = 1; i <= n; i++) { scanf ("%s", str[i]); change (str[i]); ac.insert (str[i]); } ac.build (); scanf ("%s", buf); int len = strlen (buf); change (buf); int a = 0, b = 0, c = 0, d = 0; for (int i = 0; i < len; i++) { if (buf[i] == 'a') a++; else if (buf[i] == 'b') b++; else if (buf[i] == 'c') c++; else d++; } printf ("Case %d: %d\n", ++kase, ac.query (a, b, c, d, buf)); } return 0; }
相关文章推荐
- 贩妖记 > 第十九章,旧识
- C++之模板
- PHP内存溢出解决方案
- LVM应用实例
- Java基础---枚举
- 贩妖记 > 第十八章,兵分两路
- QCustomPlot
- 理财技术
- GP2Y1010AU0F 粉尘传感器
- LeetCode 111. Minimum Depth of Binary Tree
- JS模拟bootstrap下拉菜单效果实例
- POJ 3461 kmp计算子串(可重叠)的个数
- 推荐系统中隐语义模型
- redis常见的命令
- # Android中的任务和返回栈总结
- oracle数据库的逻辑构成(表空间,schema,user,段,区,块)
- 上期ctp期货API android 客户端
- 亲子之间,在于看懂,无关耐心zz
- Codeforces Round #357 (Div. 2) 优先队列+模拟
- LSTM网络(Long Short-Term Memory )