POJ1699 Best Sequence DP DFS

题意:

给定几个长度为L的基因序列,问同时包含这几个基因序列的最小序列长度。

思路:

注意到拼装的过程中,基因序列i和基因序列j的关系无非是谁在前,谁在后。

所以DP一下:

取一个dp[i][j]代表:基因i直接接在基因j前面时,叠加后的长度-4的值。

比如i=ATGC;j=GCTA;则dp[i][j]=2.


然后对dp[i][j]进行枚举即可,因为我们要的是一个连贯的序列,所以用DFS进行枚举,即可求出最短的。 


#include<iostream>
#include<algorithm>
#define max(a,b) (a>b?a:b)
#define min(a,b) (a<b?a:b)
using namespace std;
const int N=12;
int n;
char a[N][22];
int dp[N][N];
int len[N];
bool vis[N];
int calc(int u,int v)
{
	int sum=0;
	bool flag=true;
	for(int i=1;i<=len[u]&&flag;i++)
	{
		int vpos=1;
		sum=0;
		flag=false;
		for(int j=i;j<=len[u];j++,vpos++)
		{
			if(a[u][j]!=a[v][vpos])
			{
				flag=true;
				break;
			}
			sum++;
		}
		if(!flag)
		{
			return len[u]-sum; 
		}
	}
	return len[u];
}
void make()
{
	memset(dp,0,sizeof(dp));
	for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++)
		{
			if(i==j)
				continue;
			dp[i][j]=calc(i,j);
		}
}
int dfs(int now,int step)
{
	int sum=1<<30;
	if(step==n)
	{
		return len[now];
	}
	for(int i=1;i<=n;i++)
	{
		if(!vis[i])
		{
			vis[i]=true;
			int tmp=dp[now][i];
			tmp+=dfs(i,step+1);
			vis[i]=false;
			sum=min(tmp,sum);
		}
	}
	return sum;
}
void  solve()
{
	memset(vis,0,sizeof(vis));
	int sum=1<<30;
	for(int i=1;i<=n;i++)
	{
		vis[i]=true;
		int ret=dfs(i,1);
		sum=min(sum,ret);
		vis[i]=false;
	}
	printf("%d\n",sum);
}
int main()
{
	int cases;
	scanf("%d",&cases);
	while(cases--)
	{
		scanf("%d",&n);
		for(int i=1;i<=n;i++)
		{
			scanf("%s",a[i]+1);
			len[i]=strlen(a[i]+1);
		}
		make();
		solve();
	}
	
	return 0;
}


你可能感兴趣的:(POJ1699 Best Sequence DP DFS)