现在的位置: 首页 > 综合 > 正文

POJ 3080 Blue Jeans KMP

2013年08月24日 ⁄ 综合 ⁄ 共 1437字 ⁄ 字号 评论关闭

题意: 输入M个定长为60的DNA序列(字符串),求M条DNA的最长公共子序列,若有最长的公共子序列有若干条,则输出字典序最小的。
显然是一个字符串匹配问题。第一次用KMP算法。幸好看了严蔚敏老师的数据结构视频(第11,12),讲的很细。
题解:需要注意输出字典序最小的模式序列

#include <stack>
#include <cstring>
#include <iostream>
using namespace std;
             
#define M 65
struct node { char str[M]; };
char DNA[15][M], res[M];
int next[M], n, m, flag;
stack<node> S;

void make_pattern ()  
{
	node temp;
	while ( ! S.empty() ) S.pop();
      /*  先从长度3开始枚举可能的模式序列,直至长度60,并存放入栈*/
	for ( int pl = 3; pl <= 60; pl++ )
        {
             for ( int i = 0; i <= 57; i++ )
             {
                  if ( i + pl >  60 )
                      break;
                  strncpy(temp.str,DNA[0]+i,pl);
                  temp.str[pl] = '\0';
                  S.push(temp);
             }
        }
}

void get_Next ( char p[] )   //数组可以进一步优化,但是现在懒得写了
{
    next[0] = -1;
    int i = 0, j = -1, len=strlen(p);
    while ( i < len )
   {
        if ( j == -1 || p[i] == p[j] )
        {++i; ++j;next[i] = j;}
        else j = next[j];
    }
}

/*检测某一模式序列是否是所有DNA的公共子序列,函数返回布尔值*/
bool KMP ( char p[] )
{
    get_Next(p);
    int i,j,k,len=strlen(p);
    for ( k = 1; k < m; k++ )
    {
         i = j = 0;
         while ( i < 60 && j < len )
        {
             if ( j == -1 || DNA[k][i] == p[j] )
             { ++i; ++j; }
             else
             { j = next[j];};
        }
        if ( j < len )
             return false;
     }
     /*进行到这一步说明模式序列P是所有DNA的公共子序列*/
     if ( strcmp(p,res) < 0 || res[0] == '\0' )
     /*比较P与原来的结果,取字典序小的*/
          strcpy(res,p);
     return true;
}

int main()
{
    scanf("%d",&n);
    while ( n-- )
    {
         scanf("%d",&m);
         for ( int i = 0; i < m; i++ )
         scanf("%s",&DNA[i]);   
         res[0] = '\0';
         flag = false;
         make_pattern();
         while ( ! S.empty() )
        { 
             node pat;
             pat = S.top(); S.pop();
             if ( flag ) 
            {
   /*flag=true说明已经匹配到公共子序列,即已经产生了一个可行的结果。若当前的模式序列pat.str长度小于已求出的的结果,
则可以跳出循环了,因为子序列入栈时是从短到长,所以出栈是从长到短,后面的长度一定更小。否则继续匹配,检测是否有字典序较小的*/  
	         if ( strlen(pat.str) < strlen(res) )
                     break;
                 else KMP(pat.str);
             } 
             else flag = KMP (pat.str);
        }
        if( flag )
            printf("%s\n", res);
        else
            printf("no significant commonalities\n"); 
 }
return 0;
}


抱歉!评论已关闭.