标签:
题目链接:Lost‘s revenge
解析:n个模式串,一个目标串。问目标串通过任意次交换字符最多能包含的模式串个数。(允许重叠)
字符最长是40
只需要记录ACGT出现的次数。
如果使用5维数组,显然超内存了。
假设ACGT的总数分别为num[0],num[1],num[2],num[3]
那么对于ACGT的数量分别为ABCD的状态可以记录为: (网上大神讲的,至今还没弄明白。。。求指教)
A*(num[1]+1)*(num[2]+1)*(num[3]+1) + B*(num[2]+1)*(num[3]+1)+ C*(num[3]+1) +D
这样的状态最大就是11*11*11*11
复杂度也可以承受了。
字符串可能有重复的,用int来记录数量
AC代码:
#include <cstdio> #include <iostream> #include <cstring> #include <algorithm> #include <queue> using namespace std; const int INF = 0x3f3f3f3f; struct Trie{ int next[510][4], fail[510], end[510]; int root, L; int newnode(){ for(int i=0; i<4; i++) next[L][i] = -1; end[L++] = 0; return L-1; } void init(){ L = 0; root = newnode(); } int getch(char ch){ if(ch == 'A') return 0; if(ch == 'C') return 1; if(ch == 'G') return 2; return 3; } void insert(char buf[]){ int len = strlen(buf); int now = root; for(int i=0; i<len; i++){ if(next[now][getch(buf[i])] == -1) next[now][getch(buf[i])] = newnode(); now = next[now][getch(buf[i])]; } end[now] ++; } void build(){ 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[510][11*11*11*11+5]; int bit[4]; int num[4]; int solve(char buf[]){ int len = strlen(buf); memset(num, 0, sizeof(num)); for(int i=0; i<len; i++) num[ getch(buf[i]) ] ++; bit[0] = (num[1] + 1) * (num[2] + 1) * (num[3] + 1); bit[1] = (num[2] + 1) * (num[3] + 1); bit[2] = (num[3] + 1); bit[3] = 1; memset(dp, -1, sizeof(dp)); dp[root][0] = 0; for(int A=0; A<=num[0]; A++) for(int B=0; B<=num[1]; B++) for(int C=0; C<=num[2]; C++) for(int D=0; D<=num[3]; D++){ int s = A*bit[0] + B*bit[1] + C*bit[2] + D*bit[3]; for(int i=0; i<L; i++) if(dp[i][s] >= 0){ for(int k=0; k<4; k++){ if(k == 0 && A == num[0]) continue; if(k == 1 && B == num[1]) continue; if(k == 2 && C == num[2]) continue; if(k == 3 && D == num[3]) continue; dp[ next[i][k] ][s+bit[k]] = max(dp[ next[i][k] ][s+bit[k]], dp[i][s] + end[ next[i][k] ]); } } } int ans = 0; int status = num[0]*bit[0] + num[1]*bit[1] + num[2]*bit[2] + num[3]*bit[3]; for(int i=0; i<L; i++) ans = max(ans, dp[i][status]); return ans; } }; char buf[50]; Trie ac; int main(){ #ifdef sxk freopen("in.txt", "r", stdin); #endif // sxk int n; int kase = 0; while(scanf("%d", &n) == 1 && n){ ac.init(); for(int i=0; i<n; i++){ scanf("%s", buf); ac.insert(buf); } ac.build(); scanf("%s", buf); printf("Case %d: %d\n", ++kase, ac.solve(buf)); } return 0; }
版权声明:本文为sxk原创文章,转载请附加本文链接^_^
HDU 3341 Lost's revenge (AC自动机 + DP)
标签:
原文地址:http://blog.csdn.net/u013446688/article/details/47748197