您的位置:首页 > 大数据 > 人工智能

Hdu 2457 DNA repair (字符串_AC自…

2013-08-08 23:59 417 查看
http://acm.hdu.edu.cn/showproblem.php?pid=2457

题目的大意:给定n个危险DNA序列,再给一段长度长为L的DNA序列S,

DNA序列S中可能包含危险DNA序列,可以改变S中的字符,改变一个

算一次操作,问最少操作几次可使S不含危险DNA序列并输出,

如果怎么操作都会含有危险DNA序列输出-1。

 

解题思路:采用AC自动机+dp。想法比较创新,用给定的n个

危险DNA序列,建立一个Trie 树,每个树的节点都可以看做状态

转移方程的一个 状态。即只要当前节点不为 危险节点(某个

危险DNA序列的结束位置),则此状态可取。

状态转移方程 为 dp[i][j->next[k]] =
min(dp[i][j->next[k]],dp[i-1][j] + (S[i] !=
k))

(dp[i][j]表示在我们构造解的过程中,长度为i且到节点 j位置的最少操作数,

不可达到值为inf) .

或者 我们这样看,根据危险DNA序列所建的字典树,我们用模拟的方式 ,从第一个

字符开始构造, 依次递增,找到一个满足要求的字符串,在构造此字符串的同时,比较

该字符串和输入要判断的序列S,若该位置i的字符和s[i],相同,则表示,此位置

的字符不需要改变,反则,需要把s[i]该为词字符,为一次改变操作.

所以此题中,由字典树构造失败指针时,需要考虑考虑所有存在的next 节点,

即 temp->next[i]
=NULL时,需对temp->next[i]的指向赋值,使其充当自身next节点

的失败指针的作用,确保匹配失败是可以回溯到相应节点的位置。

注意 动态规划方程中 每模拟增加一个字符,就是从j 状态节点,转到 j->next[k]状态节点


所以  dp[i][j->next[k]] 可由 dp[i-1][j]
+ (S[i] != k) 得到。

所以 最后 的结果应该是 搜 dp[len][j],0<=j<count
的最小值

 

 

//=+

#include<stdio.h>

#include<string.h>

#include<stdlib.h>

#define kind 4

#define MAX 10001

#define inf 99999

struct node

{

    int
flag;

    int num
;

    node
*next[kind];

    node
*fail;

};

node *q[MAX],tre[MAX];

char keyword[21];

char str[1001];

int dp[1010][MAX],head,tail,count;

node *root;

node * new_node(){ 

    node
*p=(struct node *)malloc(sizeof(struct node));

   
p=&tre[count];    

   
p->flag = 0;

   
p->num  = count++;

   
p->fail = NULL; 

   
memset(p->next,NULL,sizeof(p->next));  

    return
p; 



int min(int x,int y)

{

   
if(x<y)return x;

    else return
y;

}

int trs(char a)

{

   
if(a=='A')return 0;

   
if(a=='T')return 1;

   
if(a=='G')return 2;

   
if(a=='C')return 3;

}

void insert(char *word)

{

    
int index,len;

    
node *p = root,*newnode;

    
len = strlen(word);

    
for(int i=0 ;i <len  ; i++ )

    
{  

        
index=trs(word[i]);

        
if(!p->next[index])

           
p->next[index]=new_node();

        
p=p->next[index];//指针移动至下一层

        
if(p->flag)break;

    
}

    
p->flag=1;  //单词结尾 节点 flag =1
做标记  

}

void build_ac_automation()

{

    
head=0;tail=1;

    
q[head]=root;

    
node *temp,*p;

    
while(head!=tail)

    
{

        
temp=q[head++];

        
p=NULL;

        
for(int i=0;i< kind ;i ++)

        
{

            
if(temp->next[i])

         
4000
   
{

                
if(temp==root)temp->next[i]->fail=root;

                
else {

      
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: