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; }