2017.10.5 最短母串 思考记录

来源:互联网 发布:北京编程培训学校 编辑:程序博客网 时间:2024/06/09 21:16

这个题n<=15,可以用10表示选取情况下的最优值

预处理两个串之间的连接关系,然后枚举状态转移

然而这个题还要输出方案,,而且还不让你开空间。

所以只能记录前继动态判断、、

所以十分难写难调



码:

#include<iostream>#include<cstdio>#include<cstring>using namespace std;int n,i,j,k,l,lin[15],g1[16385][15],g2[16385][15],er[15],daan2[15],p;long long f[16385][15],lj[16][16],ans=2147483647,len[15];char str[15][60],daan[800],lin3[800];bool wu[15];int main(){    memset(f,0x7f,sizeof(f));    scanf("%d",&n);    for(i=1;i<=n;i++)    {    scanf("%s",str[i]+1);            len[i]=strlen(str[i]+1);    }    for(i=1;i<=n;i++)    for(j=1;j<=n;j++)    {        if(i==j||len[i]>len[j])continue;        for(k=1;k<=len[j]-len[i];k++)        {        for(l=1;l<=len[i];l++)        {      if(str[i][l]!=str[j][k+l-1])break;        }                        if(l>len[i])wu[i]=1;                    }                }    int cnt=0;    for(i=1;i<=n;i++)    {    if(wu[i])continue;++cnt;    for(j=1;j<=len[i];j++)    str[cnt][j]=str[i][j];        len[cnt]=len[i];            }    n=cnt;    for(i=1;i<=n;i++)//最长延伸(第一个串)    {        for(j=1;j<=n;j++)        {            if(i==j)continue;            for(k=1;k<=len[i];k++)            {                for(l=1;l<=len[j];l++)                {                if(str[i][k+l-1]!=str[j][l])break;                }                            if(k+l-2==len[i])                {                lj[i][j]=len[i]-k+1;                    break;                }            }        }            }    er[0]=1;    for(i=1;i<=n;i++)    er[i]=er[i-1]*2;    for(i=1;i<=n;i++)    f[er[i-1]][i-1]=len[i],g1[er[i-1]][i-1]=-1;    for(i=1;i<er[n];i++)//枚举状态    {        for(j=0;j<n;j++)//枚举上一个是啥        {                for(k=0;k<n;k++)//枚举这一个放啥        {              if(i&er[k])continue;            if(f[i|er[k]][k]==f[i][j]+len[k+1]-lj[j+1][k+1]&&f[i|er[k]][k]<=1000000000)            {            //判断字典序;;;;;//if(f[i|er[]])int lin2=0;                int lol1=i,lol2=j;        while(lol1!=-1)//拆出前继 ,放到lin里,顺序是反的         {    lin[++lin2]=lol2+1;//位置要加1     int tmp=lol1;    lol1=g1[lol1][lol2];    lol2=g2[tmp][lol2];                    }                int lin4=0;                lin[lin2+1]=0;        for(l=lin2;l>=1;l--)//倒着放字符         {            for(p=lj[lin[l+1]][lin[l]]+1;p<=len[lin[l]];p++)            {                lin3[++lin4]=str[lin[l]][p];            }        }        for(l=lj[j+1][k+1]+1;l<=len[k+1];l++)        {        lin3[++lin4]=str[k+1][l];        }//           for(int y=1;y<=lin4;y++)cout<<lin3[y];//        cout<<endl; lin2=0;                 lol1=i|er[k],lol2=k;        while(lol1!=-1)//拆出前继 ,放到daan2里,顺序是反的         {    daan2[++lin2]=lol2+1;    int tmp=lol1;    lol1=g1[lol1][lol2];    lol2=g2[tmp][lol2];                    }        //看答案是否字典序         lin4=0;         daan2[lin2+1]=0;        for(l=lin2;l>=1;l--)        {            for(p=lj[daan2[l+1]][daan2[l]]+1;p<=len[daan2[l]];p++)            {                daan[++lin4]=str[daan2[l]][p];            }        }//        for(int y=1;y<=lin4;y++)cout<<daan[y];//        cout<<endl<<endl;       bool huan=0;   for(l=1;l<=f[i|er[k]][k];l++)   {   if(lin3[l]<daan[l]){huan=1;break;}   if(lin3[l]>daan[l]){break;   }      }   if(huan)   {    g1[i|er[k]][k]=i;                g2[i|er[k]][k]=j;   }}            if(f[i|er[k]][k]>f[i][j]+len[k+1]-lj[j+1][k+1])            {                f[i|er[k]][k]=f[i][j]+len[k+1]-lj[j+1][k+1];                g1[i|er[k]][k]=i;                g2[i|er[k]][k]=j;                            }        }                }                        }    for(i=0;i<n;i++)    ans=min(ans,f[er[n]-1][i]);    for(i=1;i<=ans;i++)daan[i]='a';    for(i=0;i<n;i++)    {    if(f[er[n]-1][i]==ans)    {        int lin2=n;        int lol1=er[n]-1,lol2=i;        while(lol1!=-1)        {    lin[lin2]=lol2+1;    int tmp=lol1;    lol1=g1[lol1][lol2];    lol2=g2[tmp][lol2];                    lin2--;        }        //看答案是否字典序        int lin4=0;        for(j=1;j<=n;j++)        {            for(k=lj[lin[j-1]][lin[j]]+1;k<=len[lin[j]];k++)            {                lin3[++lin4]=str[lin[j]][k];            }        }        bool huan=0;        for(j=1;j<=ans;j++)        {            if(daan[j]>lin3[j])            {                huan=1;                              break;            }                if(daan[j]<lin3[j])            break;        } if(huan)for(k=1;k<=ans;k++)                daan[k]=lin3[k];    }        }    for(i=1;i<=ans;i++)    printf("%c",daan[i]);}


原创粉丝点击