POJ-1795-DNA Laboratory

这个题要求求最小长度的字符串,使得该字符串能够包含所给的所有的字符串。首先对于相互包含的字符串我们直接删除掉就行了,然后对于剩下的字符串我们依次去计算出拼接相同长度(前面的后缀和后面的前缀相同的长度)。然后进行状态压缩DP(过程比较麻烦),我的思路是用dp[i][j]表示在i状态下,最前面为j的时候的最小长度,至于为什么要用表示前面是为了后面更好的计算出最小的字典序(我尝试过后面,但是后面处理会非常麻烦)。求出最后DP值的时候只需要找到字典序最小的答案,然后用DFS向后搜索即可

代码:

#include<cstdio>
#include<cstring>
#include<string>
#include<iostream>
#include<algorithm>
using namespace std;
const int inf=1<<29;
const int maxn=110;
const int maxm=16;
struct String
{
    char str[maxn];
    int len;
    bool operator < (const String &a)const
    {
        return strcmp(str,a.str)<0;
    }
}str[maxm];
int n,ansl,dis[maxm][maxm],dp[1<<maxm][maxn];
string ans;
bool vis[maxm];
int Cal(int s1,int s2)
{
    int lena=str[s1].len;
    int lenb=str[s2].len;
    for(int i=max((int)(lena-lenb),0);i<=lena;i++)
    {
        bool is=true;
        for(int j=i,k=0;j<lena;k++,j++)
            if(str[s1].str[j]!=str[s2].str[k])
            {
                is=false;
                break;
            }
        if(is)
            return lena-i;
    }
    return 0;
}
void Init()
{
    for(int i=0;i<n;i++)
        for(int j=0;j<n;j++)
            if(i!=j)
                dis[i][j]=Cal(i,j);
    for(int i=0;i<(1<<n);i++)
        for(int j=0;j<n;j++)
            dp[i][j]=inf;
    for(int i=0;i<n;i++)
        dp[1<<i][i]=str[i].len;
}
void DFS(int cnt,int now,string s,int last)
{
    if(cnt==n)
    {
        if(ans==""||ans>s)
            ans=s;
        return;
    }
    int id=-1;
    string ss;
    for(int i=0;i<n;i++)
    {
        if(!vis[i]&&dp[now][last]==dp[now^(1<<last)][i]+str[last].len-dis[last][i])
        {
            string s1=s;
            for(int j=dis[last][i];j<str[i].len;j++)
                s1+=str[i].str[j];
            if(id==-1||ss>s1)
            {
                ss=s1;
                id=i;
            }
        }
    }
    vis[id]=1;
    DFS(cnt+1,now^(1<<last),ss,id);
}
int main()
{
    int T,cas=1;
    scanf("%d",&T);
    while(T--)
    {
        ansl=inf;
        scanf("%d",&n);
        int cnt=0;
        for(int i=0;i<n;i++)
        {
            scanf("%s",str[cnt].str);
            str[cnt].len=strlen(str[cnt].str);
            for(int j=0;j<cnt;j++)
            {
                if(strstr(str[j].str,str[cnt].str)!=NULL)
                {
                    cnt--;
                    break;
                }
                if(strstr(str[cnt].str,str[j].str)!=NULL)
                {
                    strcpy(str[j].str,str[cnt].str);
                    str[j].len=strlen(str[j].str);
                    cnt--;
                    break;
                }
            }
            cnt++;
        }
        n=cnt;
        sort(str,str+n);
        Init();
        for(int i=0;i<(1<<n);i++)
            for(int j=0;j<n;j++)
                if(dp[i][j]!=inf&&(i&(1<<j)))
                    for(int k=0;k<n;k++)
                        if(!(i&(1<<k)))
                            dp[i|(1<<k)][k]=min(dp[i|(1<<k)][k],dp[i][j]+str[k].len-dis[k][j]);
        int pos=0;
        for(int i=1;i<n;i++)
            if(dp[(1<<n)-1][i]<dp[(1<<n)-1][pos])
                pos=i;
        memset(vis,0,sizeof(vis));
        vis[pos]=1;
        ans="";
        DFS(1,(1<<n)-1,string(str[pos].str),pos);
        printf("Scenario #%d:\n",cas++);
        printf("%s\n",ans.c_str());
        printf("\n");
    }
    return 0;
}


你可能感兴趣的:(dp,状态压缩)