HNU City Merger 【状态压缩DP】

题意: 求出包含样例所有子串的字符串的最小长度。

分析: dp[i][j] 表示在 i 状态下 ,以第 j 个字符串结尾的最优值。

#include<stdio.h>
#include<string.h>
#define INF 0x1f1f1f1f
#define clr(x)memset(x,0,sizeof(x))
int min(int a,int b)
{
    return a<b?a:b;
}
int dp[1<<16][16];
int g[16][16];
int add_s(char *s1,char *s2)  // 求出 s2 串加在s1 串后增加的长度
{
    int i,j;
    int l1=strlen(s1);
    int l2=strlen(s2);
    for(i=0;i<l1;i++)
    {
        for(j=i;j<l1&&j-i<l2;j++)
            if(s1[j]!=s2[j-i])
                break;
        if(j==l1)
            return l2-(l1-i);
        if(j-i==l2)
            return 0;
    }
    return l2;
}
int main()
{
    int st,stat,i,j,k,n,tot,flag;
    char s[16][22];
    while(scanf("%d",&n)!=EOF)
    {
        if(n==0)
            break;
        for(i=0;i<n;i++)
            scanf("%s",s[i]);
        tot=0;
        for(i=0;i<n;i++)                        // 去掉被包含的样例串 
        {
            flag=1;
            for(j=0;j<n;++j)
                if(i!=j&&strstr(s[j],s[i])) 
                    flag=0;
            if(flag)
                strcpy(s[tot++], s[i]);
        }
        n=tot;
        st=(1<<n)-1;
        for(i=0;i<n;i++)  
            for(j=0;j<n;j++)
                  g[i][j]=add_s(s[i],s[j]);
        memset(dp,INF,sizeof(dp));
        for(i=0;i<n;i++)
            dp[1<<i][i]=strlen(s[i]);
        for(i=1;i<st;i++)
            for(j=0;j<n;j++)
            {
                if(dp[i][j]==INF)     // 状态 i 中不包含 j 这个串
                    continue;
                for(k=0;k<n;k++)
                {
                    if(i&(1<<k))
                        continue;  // 状态 i 中包含了 第 k 个串
                    stat=i+(1<<k);
                    dp[stat][k]=min(dp[stat][k],dp[i][j]+g[j][k]);
                }
            }
        int res=INF;
        for(i=0;i<n;i++)
            res=min(res,dp[st][i]);
        printf("%d\n",res);
    }
    return 0;
}

 

posted @ 2012-09-04 21:01  'wind  阅读(240)  评论(0编辑  收藏  举报