题目:输入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;
}