您的位置:首页 > 其它

poj3691(ac自动机+dp)

2017-04-06 01:41 176 查看
Description

Biologists finally invent techniques of repairing DNA that contains segments causing kinds of inherited diseases. For the sake of simplicity, a DNA is represented as a string containing characters ‘A’, ‘G’ , ‘C’ and ‘T’. The repairing techniques are simply to change some characters to eliminate all segments causing diseases. For example, we can repair a DNA “AAGCAG” to “AGGCAC” to eliminate the initial causing disease segments “AAG”, “AGC” and “CAG” by changing two characters. Note that the repaired DNA can still contain only characters ‘A’, ‘G’, ‘C’ and ‘T’.

You are to help the biologists to repair a DNA by changing least number of characters.

题意:

最少改变主串多少个字符使得他不包括任何模式串

tip:

dp[i][j]表示主串走了i个字母,当前在自动机的j节点,

然后枚举j的4个可能孩子k。。。注意是强行在第j节点,如果s[i] != ch[j][k] 很明显答案+1 相当于把s[i]强行改成ch[j]k。。。

dp[i+1][v] = min(dp[I][j])

这个v不单单是孩子,还可能是fail的孩子。注意细节

#include <cstdio>
#include <iostream>
#include <cstring>
#include <queue>
using namespace std;
int n,m,node;
const int INF = (1<<30);
const int maxn = 1005;
char ss[55][25],s[maxn];
int val[maxn],last[maxn],ch[maxn][5],fail[maxn];

int getpos(char a){
if(a == 'A')    return 0;
if(a == 'T')    return 1;
if(a == 'C')    return 2;
if(a == 'G')    return 3;
}

void Insert(int v){
int len = strlen(ss[v]);
int tmp = 0;
for(int i = 0; i < len ; i++){
int pos = getpos(ss[v][i]);
if(ch[tmp][pos] == 0){
memset(ch[node],0,sizeof(ch[node]));
val[node] = 0;
ch[tmp][pos] = node++;
}
tmp = ch[tmp][pos];
}
val[tmp] = v;
}

void getfail(){
queue<int> q;
int u = 0;
for(int i = 0; i < 4; i++){
if(ch[u][i]){
int tmp = ch[u][i];
fail[tmp] = 0;
q.push(tmp);
last[tmp] = 0;
}
}

while(!q.empty()){
int tmp = q.front();
q.pop();
for(int i = 0; i < 4; i++){
if(ch[tmp][i]){
int v = fail[tmp];
while(v && ch[v][i]==0) v = fail[v];
fail[ch[tmp][i]] = ch[v][i];
q.push(ch[tmp][i]);
last[ch[tmp][i]] = val[fail[ch[tmp][i]]]?fail[ch[tmp][i]] : last[fail[ch[tmp][i]]];
}
}
}
}

void init(){
node = 1;
memset(ch[0],0,sizeof(ch[0]));
memset(last,0,sizeof(last));
for(int i = 1; i <= m ; i++){
scanf("%s",ss[i]);
Insert(i);
}

}
int dp[maxn][maxn];
void sov(){
scanf("%s",s);
int len = strlen(s);
for(int i = 0 ; i <= len ; i++)
for(int j =  0 ; j <= node; j++)
dp[i][j] = INF;
dp[0][0] = 0;

for(int i = 0 ; i < len; i++){
for(int j = 0 ; j < node; j++){
if(dp[i][j] == INF) continue;
for(int k = 0 ; k < 4; k++){
int v;
if(ch[j][k])    v = ch[j][k];
else{
v = fail[j];
while(v &&ch[v][k] == 0) v = fail[v];
v = ch[v][k];
}
if(last[v]||val[v]) continue;

if(getpos(s[i]) == k)
dp[i+1][v] = min(dp[i+1][v],dp[i][j]);
else
dp[i+1][v] = min(dp[i+1][v],dp[i][j]+1);
}
}
}
int ans = INF;
for(int i = 0 ; i < node; i++){
// printf("dp[%d] = %d\n",i,dp[len][i]);
ans = min(ans,dp[len][i]);
}
if(ans == INF)  printf("-1\n");
else printf("%d\n",ans);
}

int main(){
int ca = 1;
while(~scanf("%d",&m)&&m){
init();
//cout <<ch[0][1]<<endl;

printf("Case %d: ",ca++);
getfail();
//        for(int i =  0 ; i < node ; i++)
//            printf("last[%d] = %d\n",i,last[i]);
sov();
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  dp ac自动机