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;

}

 

你可能感兴趣的:(sequence)