L - DNA sequence

简单搜索&&进阶搜索 - Virtual Judge (vjudge.net)

【题目描述】

现在我们给定了数个DNA序列,请你构造出一个最短的DNA序列,使得所有我们给定的DNA序列都是它的子序列。
例如,给定"ACGT", "ATGC", "CGTT", "CAGT", 你可以构造的一个最短序列为"ACAGTGCT",但是需要注意的是,这并不是此问题的唯一解。

【输入】

第一行含有一个数t,代表数据组数。
每组数据的第一行是一个数n,代表给定的DNA序列数量;接下来的n行每行一个字符串s,代表给定的n个DNA序列。
1<=n<=8,1<=|s|<=5

【输出】

对于每一组数据,输出一行中含有一个数,代表满足条件的最短序列的长度。

解题思路

这个题要求最短的序列,那么我们肯定要从一个小的长度开始往大的长度遍历,而且对于 DNA 字符串有很多种情况,每个字符的位置可以放四种‘A’,'C','T','G',而对于这么多种情况,可能不能直接用 dfs 一条路走到底,再走第二条,第三条……最后找到最短的序列是多少。

所以要想办法简化搜索,如果明明可以判断这条路一直走肯定会超过最大的值,就不继续进行搜索了。

对于简化搜索,如果判断的时间复杂度还很高,也很不划算,所以只要粗略地估计,其中用 getst()函数来实现,返回找到的还需要增加的步数。

x 是已经放置的字母数,maxt 是传入的希望的最小字母数(如果当前的 maxt 不满足要求,就自增,一步一步找它的最小值)其中(getst()+x)>maxt 时就不要往这个方向搜索了(这是最理想的情况,因为希望的是:有几个字符串中的字母少了,但是只要添加一个字母,所有的字符串的字母都增加一个)。

代码如下:

#include<iostream>
#include<string>
#include<stdio.h>
using namespace std;
char a[10][10];
char dna[5] = { 'A','C','T','G' };
int book[10];//匹配到的位置
int len[10];
int n, maxt;
int maxd(int x, int y)
{
	if (x > y)
		return x;
	else
		return y;
}
int getst()
{
	int m = 0;
	//大致计算出当前拼接的字符串还需要拼接多少个字母
	//用一层循环大概计算,其中(gets()+maxt<=实际拼接次数)
	//最理想的情况是:有字符串的字母少了,但是只要添加一个字母,所有的字符串的字母都增加一个
	for (int i = 0; i < n; i++)
	{
		m = maxd(m, len[i] - book[i]);
	}
	return m;
}
int check(int x)
{
	int i, j, w;
	w = getst();
	if (x + w > maxt)
		return 0;
	if (w == 0)
		return 1;
	for (i = 0; i < 4; i++)
	{
		int k[10], flag=0;
		memcpy(k, book, sizeof(book));//记录book数组,否则后面变化后找不到了
		for (j = 0; j < n; j++)
		{
			if (dna[i] == a[j][book[j]])
			{
				flag = 1;
				book[j]++;
			}
		}
		if (flag == 1)
		{
			if (check(x + 1))
				return 1;
			//回溯,如果进入该层循环后,不符合,就将先前记录的k数组的值放入book数组
			memcpy(book, k, sizeof(k));
		}
	}
	return 0;
}
int IDA()
{
	while (check(0)==0)
		maxt++;
	return 1;
}
int main()
{
	int t, i, j;
	scanf("%d", &t);
	while (t--)
	{
		memset(book, 0, sizeof(book));
		memset(len, 0, sizeof(len));
		scanf("%d", &n);
		for (i = 0; i < n; i++)
		{
			scanf("%s", a[i]);
			len[i] = strlen(a[i]);
		}
		maxt = 0;
		if(IDA())
			printf("%d\n",maxt);
	}
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

明里灰

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值