pku 1699 Best Sequence 状态压缩dp

http://poj.org/problem?id=1699

DFS+剪枝解法http://www.cnblogs.com/E-star/archive/2012/08/10/2631584.html

题意:

现在给出几个基因片段,要求你将它们排列成一个最短的序列,序列中使用了所有的基因片段,而且不能翻转基因。,这些基因可以重叠,只要一个基因的后段和一个基因的前端一样,就可以将其重叠链接在一起。现问将这些 基因全部排列出来,最短的长度为多少。

思路:

将n个基因片段的所有状态压缩,dp[i][j]表示状态i以j基因片段结尾的最短长度,则有

dp[i][j] = min(dp[i][j],dp[tmp][k] + len[j] - share[k][j])

tmp表示i状态除去j状态后,以k结尾的最短长度,然后dp[tmp][k] + len[j] - share[k][j]表示连接上后的长度。

View Code
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
#define N 12
#define maxn 22
using namespace std;

const int inf = 0x7fffffff;

char str[N][maxn];
int dp[1<<N][maxn];
int len[N],share[N][N],n;

int getR(int x,int y)
{
    int i,j,l;
    int L = 0;
    for (l = 0; l <= len[x] && l <= len[y]; ++l)
    {
        bool flag = false;
        for (i = len[x] - l,j = 0; i < len[x] && j < l; ++i,++j)
        {
            if (str[x][i] != str[y][j])
            {
                flag = true;
                break;
            }
        }
        if (!flag) L = l;
    }
    return L;
}
void init()
{
    int i,j;
    memset(share,0,sizeof(share));
    for (i = 0; i < n; ++i)
    {
        for (j = 0; j < n; ++j)
        {
          share[i][j] = getR(i,j);
        }
    }
}
int main()
{
   // freopen("d.txt","r",stdin);
   int i,j,t,k;
   scanf("%d",&t);
   while (t--)
   {
       scanf("%d",&n);
       for (i = 0; i < n; ++i)
       {
           scanf("%s",str[i]);
           len[i] = strlen(str[i]);
       }
       init();//计算共享长度
       int nn = (1<<n) - 1;//存储所有的状态
       for (i = 1; i <= nn; ++i)
       {
           for (j = 0; j < n; ++j)
           {
               dp[i][j] = inf;//初始化
               if (i&(1<<j))//如果j存在于i状态里面
               {
                   int tmp = i - (1<<j);
                   if (tmp == 0)//如果只存在j状态
                   {
                       dp[i][j] = len[j];
                       continue;
                   }
                   for (k = 0; k < n; ++k)
                   {
                       if (tmp&(1<<k))
                       {
                           dp[i][j] = min(dp[i][j],dp[tmp][k] + len[j] - share[k][j]);
                       }
                   }
               }
           }
       }
       int Min = inf;
       for (i = 0; i < n; ++i)
       {
           if (dp[nn][i] < Min)
           {
               Min = dp[nn][i];
           }
       }
       printf("%d\n",Min);
   }
    return 0;
}

 

posted @ 2012-08-10 18:14  E_star  阅读(192)  评论(0编辑  收藏  举报