向前走莫回头❤

【NOIP 模拟题】[山东多校联合模拟赛 day1 T2] 祖先(dp)

2.祖先(ancestor.cpp/c/pas)

【问题描述】
  任何一种生物的 DNA 都可以表示为一个由小写英文字母组成的非空字符串。科学家发现,所有的生物都有可能发生变异。所谓变异,就是子代的 DNA 串与父代的 DNA 串有差异。每次变异, DNA 串中恰好有一个字符会变成两个任意的字符。一共有 n 种可能的变异。
变异 ai->bici 表示字符 ai 有可能变异为两个字符 bici。

  详细来说,就是删掉一个字符 ai,之后在原来 ai 的位置处,插入 bi,ci 两个字符(注意字符 bi 必须在 ci 的前面)。每种变异都有可能发生任意多次。可以发现,每变异一次,DNA 串的长度会加 1。
  如果有一种生物 a,他的 DNA 串是 s1,另外存在一种生物 b,他的 DNA 串是 s2。如果 s2 可以通过若干次变异变为 s1,那么生物 b 就被叫做生物 a 的祖先。
  现在,给定一种生物,他的 DNA 串是 s。请找出他的一个祖先,且这个祖先的 DNA 串尽量短。
【输入】
  输入文件 ancestor .in,共 n+2 行。
  第一行包含一个非空字符串 s。
  第二行含有一个整数 n,表示所有可能的变异。
  接下来 n 行,每行描述一种可能的变异,按照 ai->bici 的格式。s,ai,bi,ci 仅包含小写英文字母。
  请注意:一种变异可能出现多次。
【输出】
  输出文件名为 ancestor .out。
  输出只有一行,一个整数,表示祖先 DNA 串的最短长度。
【输入输出样例 1】

  ancestor.in 
   ababa
   2
   c->ba

  ancestor.out
   2
【输入输出样例 2】
  ancestor.in  

   ababa
   7
   c->ba
   c->cc
   e->ab
   z->ea
   b->ba
   d->dd

   d->ab

  ancestor.out
   1
【数据范围】
  对于 30%的数据,s 的长度<=5,N <= 3;
  对于 100%的数据,s 的长度<=50,N <= 50 

——————————————————————————————————————————————————————————————

【题解】【dp】

【ch[i][j][k]表示i-j位能否是k;list[i][1]表示第i种替换后的字符,list[i][2]、list[i][3]表示第i种替换前的字符;f[i][j]表示i-j位替换后是几个字符】

【先预处理出ch数组,然后根据ch数组进行dp,最后输出f[1][len]】

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
char s[60];
int ch[60][60][30],list[60][5],f[60][60];
int len,n;
int main()
{
	freopen("ancestor.in","r",stdin);
	freopen("ancestor.out","w",stdout);
	int i,j,k,l;
	scanf("%s",s+1); 
	len=strlen(s+1);
	for(i=1;i<=len;++i) ch[i][i][s[i]-'a']=1;
	scanf("%d\n",&n);
	for(i=1;i<=n;++i)
	 {
	 	char ss[10];
	 	gets(ss);
	 	list[i][1]=ss[0]-'a';
	 	list[i][2]=ss[3]-'a';
	 	list[i][3]=ss[4]-'a';
	 }
	for(i=len;i>0;--i)
	 for(j=i+1;j<=len;++j)
	  for(k=i;k<j;++k)
	   for(l=1;l<=n;++l)
	    if(ch[i][k][list[l][2]]&&ch[k+1][j][list[l][3]]) ch[i][j][list[l][1]]=1;
	for(i=len;i>0;--i)
	 for(j=i;j<=len;++j)
	  {
	  	bool b=0;
		for(k=0;k<26;++k)
	  	 if(ch[i][j][k]) f[i][j]=1,b=1;
	  	if(!b)
	  	 {
	  	 	f[i][j]=0x7fffffff;
	  	 	for(k=i;k<j;++k)
	  	  	  if(f[i][k]+f[k+1][j]<f[i][j]) f[i][j]=f[i][k]+f[k+1][j];
		   }
	  }
	printf("%d\n",f[1][len]);
	return 0;
}


dp弱爆啦 一遇dp就爆零……(忧桑忧桑)

posted @ 2016-08-23 15:46  lris0-0  阅读(79)  评论(0编辑  收藏  举报
过去的终会化为美满的财富~o( =∩ω∩= )m