UVa 1368 DNA Consensus String (DNA序列)

UVa 1368 DNA Consensus String (DNA序列)_第1张图片UVa 1368 DNA Consensus String (DNA序列)_第2张图片UVa 1368 DNA Consensus String (DNA序列)_第3张图片UVa 1368 DNA Consensus String (DNA序列)_第4张图片UVa 1368 DNA Consensus String (DNA序列)_第5张图片

题意:

给一些DNA序列(字符串只包含ACGT四种字母),求一个与这些DNA序列Hamming距离和最小的字符串,如果有多个这种字符串则输出字典序最小的那个,并求出最小Hamming距离和。

两个等长字符串的Hamming距离等于字符不同的位置的个数。

例如:ACGT和GCAT的Hamming距离是2.(左数第1,4个字符不同)

思路:

具体到每个位置考虑。最终的字符串在每个位置上的字母一定都是和输入DNA序列相应位置重合次数最多的那个。

因此只需统计输入所有DNA序列在每个位置重复出现字母次数。

用a[0][i], a[1][i], a[2][i], a[3][i]分别表示A,C,G,T在第i个位置(起始位置是0)出现的次数和

在该位置上的Hamming距离和是:

m-Max[i];Max[i]是输入DNA序列在位置i最大重合次数,即

Max[i] = max(a[0][i], a[1][i], a[2][i], a[3][i]);

但是同时又需要考虑这个最大重合次数的字母是什么,所以可以在max函数添加一个变量,用以标记最大的字母下标index,此下标与a[0][i], a[1][i], a[2][i], a[3][i]中的0,1,2,3相照应,因此初始化一个字符数组即可。

s1[4] = { 'A','C','G','T' };

#include 
#include 
#define maxn 1010
int max(int a, int b, int c, int d, int *inde)
{
	int max1;
	max1 = a > b ? a : b;
	max1 = max1 >= c ? max1 : c;
	max1 = max1 >= d ? max1 : d;
	if (max1 == a) *inde = 0;
	else if (max1 == b) *inde = 1;
	else if (max1 == c) *inde = 2;
	else *inde = 3;
	return max1;
}
int main()
{
	//freopen("in.txt", "r", stdin);
	//freopen("out.txt", "w", stdout);
	int T, m, n, i, j;
	char s[50][maxn], s1[4] = { 'A','C','G','T' };
	int a[4][maxn],index[maxn],Max[maxn];
	scanf("%d", &T);
	while (T--)
	{
		scanf("%d%d", &m, &n);
		for (i = 0;i < m;i++)
			scanf("%s", s[i]);
		memset(a, 0, sizeof(a));
		for (i = 0;i < n;i++)
		{
			for (j = 0;j < m;j++)
			{
				if (s[j][i] == 'A') a[0][i]++;
				else if (s[j][i] == 'C') a[1][i]++;
				else if (s[j][i] == 'G') a[2][i]++;
				else a[3][i]++;
			}
			Max[i] = max(a[0][i], a[1][i], a[2][i], a[3][i], &index[i]);
		}
		int dis = 0;
		for (i = 0;i < n;i++)
		{
			putchar(s1[index[i]]);
			dis += m - Max[i];
		}
		printf("\n%d\n", dis);
	}
	return 0;
}


你可能感兴趣的:(算法竞赛入门经典(第2版))