POJ 3691 DNA repair ( Trie圖 && DP )
阿新 • • 發佈:2017-10-12
queue src can bsp next mem %d mil ++
題意 : 給出 n 個病毒串,最後再給出一個主串,問你最少改變主串中的多少個單詞才能使得主串中不包含任何一個病毒串
分析 : 做多了AC自動機的題,就會發現這些題有些都是很套路的題目。在構建 Trie 圖的時候給病毒串末尾打上標記,最後定義DP[i][j] = 長度為 i 的串在 j 這個狀態節點最少改變數使得其不包含病毒串,則狀態轉移方程
if(Trie[k]不是被標記的病毒節點) DP[i+1][j] = min( DP[i+1][j], DP[i][k] + (mp[S[i]] != k) )
k 為 j 節點的四個下一狀態,轉到"ATGC"其中一個,而mp[]作用是把"ATGC"轉為0、1、2、3
DP的初始狀態為 DP[0][0] = 0,DP[0~len][0~節點數] = INF
具體的看代碼即可
#include<queue> #include<stdio.h> #include<string.h> using namespace std; const int Max_Tot = 1111; const int Letter = 4; const int INF = 0x3f3f3f3f; int mp[128]; struct Aho{ struct StateTable{ int Next[Letter];View Codeint fail, flag; }Node[Max_Tot]; int Size; queue<int> que; inline void init(){ while(!que.empty()) que.pop(); memset(Node[0].Next, 0, sizeof(Node[0].Next)); Node[0].fail = Node[0].flag = 0; Size = 1; } inline void insert(char *s){ int now = 0; for(int i=0; s[i]; i++){ int idx = mp[s[i]]; if(!Node[now].Next[idx]){ memset(Node[Size].Next, 0, sizeof(Node[Size].Next)); Node[Size].fail = Node[Size].flag = 0; Node[now].Next[idx] = Size++; } now = Node[now].Next[idx]; } Node[now].flag = 1; } inline void BuildFail(){ Node[0].fail = 0; for(int i=0; i<Letter; i++){ if(Node[0].Next[i]){ Node[Node[0].Next[i]].fail = 0; que.push(Node[0].Next[i]); }else Node[0].Next[i] = 0;///必定指向根節點 } while(!que.empty()){ int top = que.front(); que.pop(); if(Node[Node[top].fail].flag) Node[top].flag = 1; for(int i=0; i<Letter; i++){ int &v = Node[top].Next[i]; if(v){ que.push(v); Node[v].fail = Node[Node[top].fail].Next[i]; }else v = Node[Node[top].fail].Next[i]; } } } }ac; char S[1111]; int dp[1111][1111]; int main(void) { mp[‘A‘] = 0, mp[‘T‘] = 1, mp[‘G‘] = 2, mp[‘C‘] = 3; int n, Case = 1; while(~scanf("%d", &n) && n){ ac.init(); for(int i=0; i<n; i++){ scanf("%s", S); ac.insert(S); } ac.BuildFail(); scanf("%s", S); int len = strlen(S); for(int i=0; i<=len; i++) for(int j=0; j<=ac.Size; j++) dp[i][j] = 2333; dp[0][0] = 0; for(int i=0; i<len; i++){ for(int j=0; j<ac.Size; j++){ if(dp[i][j] != 2333){ for(int k=0; k<4; k++){ int newi = i+1; int newj = ac.Node[j].Next[k]; if(!ac.Node[newj].flag){ dp[newi][newj] = min(dp[newi][newj], dp[i][j] + (k != mp[S[i]]) ); } } } } } int ans = 2333; for(int i=0; i<ac.Size; i++) ans = min(ans, dp[len][i]); printf("Case %d: ", Case++); if(ans != 2333) printf("%d\n", ans); else puts("-1"); } return 0; }
POJ 3691 DNA repair ( Trie圖 && DP )