DNA

DNA

Time Limit:5000MS  Memory Limit:65536K
Total Submit:65 Accepted:5

Description

DNA能够表达数以百万计的基因密码,所用的仅仅是4种分子。我们分别用A、G、T和C表示这4种分子。一条基因就是DNA链上的一个由这4种分子组成的片段。人体按照一条基因上的分子序列可以合成出一种蛋白质。一条基因片段对应着一种蛋白质。 
现在给定每种基因能合成出来的蛋白质的分数。但是,在蛋白质合成时,同一条DNA链可以用不同的方式解释出不同的基因片段。比如说,一条DNA链AATGCGG,可以解释出AATG 和 GG 这两个基因片段,也可以解释出AT 和 GCCG这两个基因片段。在同一种解释中,不得出现重叠的片段。你的任务是,仔细安排一条DNA链上的基因,让它能合成出来的蛋白质的分数总和最大。 



Input

输入多个测试用例。每个测试用例的第一行是一个整数N(1 < N ≤ 100,000);接下来有N行,每行包括一个长度不超过10的表示基因片段的串S和一个整数C(按照基因片段S合成的蛋白质的分数);每个测试用例的最后一行是长度不超过1000的串(一条DNA链)。

Output

按照输出样例的格式输出每个测试用例的DNA链能合成的蛋白质的分数总和的最大值。

Sample Input

4
AATG 3
AT 2
GCGG 3
GG 2
AATGCGG
3
A 1
C 1
G 1
T

Sample Output

Case 1: 5
Case 2: 0

树形DP。。 DP+字典树。

状态转移方程很容易得出   那就是

DP[i]=max(dp[i-1],dp[i-k]+val,dp[i])( k就是子串的长度)

但是直接模拟应该会超时,所以要用字典树存储。

我是把每个字符串逆序存储的。。方便我这个转移方程。


下面是AC代码:

#include<iostream>
using namespace std;
#define N 100009

char input[1024],buff[1024];
int dp[1009];
int max(int a,int b){ return a>b?a:b;}
struct t_node
{
	bool f;
	int len,val;
	int next[26];
	void init(){   f=0; memset(next,-1,sizeof(next)); }
}trie[N*3];
int p;
void root ()
{	trie[p=0].init();   }
void insert(char *a,int val)
{
	int index=0;
	int len=strlen(a);
	int cur,i;
	for(i=len-1;i>=0;i--)
	{
		cur=a[i]-'A';
		if(trie[index].next[cur]==-1)
		{
			trie[++p].init();
			trie[index].next[cur]=p;
		}
		index=trie[index].next[cur];
	}
	trie[index].f=1;
	trie[index].len=len;
	trie[index].val=val;

}
int find(char *a,int k)
{
	int index=0,i,cur;
	int len=strlen(a);
	for(i=len-1;i>=0;i--)
	{

		cur=a[i]-'A';

		if(trie[index].next[cur]==-1)
			return 0;
		
		index=trie[index].next[cur];
		if(trie[index].f==1)
		{
    		 dp[k+1]=max(dp[k+1],dp[k+1-trie[index].len]+trie[index].val);
		}
	}


	return 0;
}


int main()
{
	int n,i,k=0;
	int len,val;
	while(scanf("%d",&n)!=EOF)
	{
		root();
		for(i=0;i<n;i++)
		{
			scanf("%s%d",buff,&val);
			insert(buff,val);
		}

		scanf("%s",input);

		len=strlen(input);

		memset(dp,0,sizeof(dp));

		for(i=0;i<len;i++)
		{
			dp[i+1]=dp[i];
		
			strncpy(buff,input,i+1);
			buff[i+1]='\0';

		//	printf("%s\n",buff);
			find(buff,i); 	
		//	printf("%d\n",dp[i]);
		}

		printf("Case %d: ",++k);
		printf("%d\n",dp[len]);

	}
	return  0;
}



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值