DNA序列(DNA Consensus String,UVa1368)(算法竞赛入门经典习题3-7) C++

题目:输入m个长度为n的DNA序列,求一个到所有序列的总hamming值之和最小的DNA序列。两个等长度的字符串的hamming值为字符不同的位置个数,如AGCT与AGAC的hamming值是2(下标为2,3位的字符不同,个数是两个)。题目要求找到hamming值最小的那个DNA序列,若存在多解,找出字典序最小的那个。具体输入输出请看原题。

思路:m个长度为n的DNA序列看作二维字符数组的输入就可以了,然后对于hamming的理解要拐个弯,看着没头绪,但其实把一个DNA的组合序列排出来看就能理解。例如,

TAGAC

TTCCT

TACCC

AACAC

对于这样一个输入,怎么找hamming最小的DNA答案序列呢,我们已知两个等长度的字符串的hamming值为字符不同的位置个数,答案的DNA序列是和题目等长度的一个序列,我们按列看,第一列T有3个,而A只有1个,那么如果我们答案序列里第一个取T,那么对于第一列的hamming就只有1,后面几列以此类推,最终可以知道答案序列为TACAC(按列竖着看哦)。

再看这个例子的第四列,为什么我们不取C而取A呢,因为题目要求存在多个解时取字典序最小的,因此在这里多判断一下即可,方法有很多,思路有就行。

代码如下,已通过VJ测试!

#include<bits/stdc++.h>
using namespace std;
char dna[55][1005];	//DNA序列组合矩阵
char a[1005];	//最小hamming距的DNA序列
int d[1000];	//记录AGCT各自出现次数

int main()
{
	int	T;
	cin >> T;
	while (T--)
	{
		int m, n;
		char ch;
		int hamming = 0;
		cin >> m >> n;
		ch = getchar();	//吃掉多余换行符

		for (int i = 0; i < m; i++)	//创建DNA序列组合矩阵
		{
			for (int j = 0; j < n; j++)
			{
				ch = getchar();
				dna[i][j] = ch;
			}
			ch = getchar();
		}
		
		//接下来,按列查找出每列最多的那个DNA元素即是该列hamming最小的答案(若出现多个答案,取字典序小的,这里直接从字典序小的开始比,避免多个答案再判断的情况)
		for (int y = 0; y < n; y++)	//创建DNA序列组合矩阵
		{
			memset(d, 0, sizeof(d));	//对每列AGCT的记录重置
			for (int x = 0; x < m; x++)
			{
				if (dna[x][y] == 'A')
					d['A']++;
				else if (dna[x][y] == 'G')
					d['G']++;
				else if (dna[x][y] == 'C')
					d['C']++;
				else if (dna[x][y] == 'T')
					d['T']++;
			}
			//找到每列最多的是哪个(顺序按字典序从小到大,一旦找到就continue循环进入下一列)
			if (d['A'] >= d['G'] && d['A'] >= d['C'] && d['A'] >= d['T'])
			{
				a[y] = 'A';
				hamming += (m - d['A']);
				continue;
			}
			else if (d['C'] >= d['A'] && d['C'] >= d['G'] && d['C'] >= d['T'])
			{
				a[y] = 'C';
				hamming += (m - d['C']);
				continue;
			}
			else if (d['G'] >= d['A'] && d['G'] >= d['C'] && d['G'] >= d['T'])
			{
				a[y] = 'G';
				hamming += (m - d['G']);
				continue;
			}
			else if (d['T'] >= d['A'] && d['T'] >= d['G'] && d['T'] >= d['C'])
			{
				a[y] = 'T';
				hamming += (m - d['T']);
				continue;
			}
		}

		//输出答案DNA序列d和hamming值
		for (int i = 0; i < n; i++)
			cout << a[i];
		cout << endl;
		cout << hamming << endl;
	}

	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值