UVA - 1368 DNA Consensus String

//法一
//这题算是初等贪心的思路了,要求总harmming距离最小,通过使每一位上选取的字母,都能使该位对总harming距离的贡献最小,按照定义,也就是所有DNA在该位置上,ATCG字母究竟哪个最多,若多个最多,就选字典序小的...思路确实挺巧妙,值得琢磨
//顺带提一下,不知道为什么,看了别人的代码,发现有人将变量作为数组维度,即在main函数内部,char DNA[m][n+1];时,居然能AC,不是说数组的维度只能是常量吗?


#include <bits/stdc++.h>
using namespace std;
const int N = 1005;
const int M = 50;
char DNA[M][N];
int num[4];

int main()
{
	int t, m, n; //m是数目,n是长度
	cin >> t;
	while (t--)
	{
		int sum = 0;
		cin >> m >> n;
//		char DNA[m][n+1];
		
		for (int i = 0; i < m; i++) cin >> DNA[i];
		for (int i = 0; i < n; i++) 
		{
			memset(num, 0, sizeof(num));
			
			for (int j = 0; j < m; j++)
			switch(DNA[j][i])
			{
				case 'A' :num[0]++;break;
				case 'C' :num[1]++;break;
				case 'G' :num[2]++;break;
				case 'T' :num[3]++;break;
			}
			
			int temp = num[0], ans = 0;
			for (int j = 1; j < 4; j++)
			{
				if (num[j] > temp)
				{
					ans = j; temp = num[j]; 
				}
			}
			sum += m - temp;
			
			switch(ans)
			{
				case 0: cout << "A";break;
				case 1: cout << "C";break;
				case 2: cout << "G";break;
				case 3: cout << "T";break;
			}  
		}
		cout << endl << sum << endl;
		
	} 
	return 0;
}
/*
  法二:
  
  用结构体真的能让代码简单很多很多...
 这个思路有个比较巧妙的地方,在于:将Harming距离所要求的,与对应字符不同的字符个数,转换为与对应字符相同的个数,然后再用总数(DNA个数)减去相同的个数
 
 其实不用这个思路也可以,但是会比较繁琐,例如我假设最终求得的那个DNA的,某个位置是A,那么所有m条DNA,对于每一条而言,如果对应的这个位置不是A,那么这个位置对应的G\C\T都要加1,繁琐且易错...而如果转变思路,用m减去相同的,需要更新的就只有该位置的A (这种思路下,记录的就是,当前位置下,ATCG分别会和几条DNA的该位置,对总harming距离作出贡献,这就真的是取最小值了)
*/

#include <bits/stdc++.h>
using namespace std;
const int N = 1005;
char check[N];
char ans[N];
struct DNA
{
	int a, c, g, t;
	void clearall()
	{
		a = c = g = t = 0;
	}
	int getmax(char& ch)//此处很多地方要用偏序的不等号,因为有多个答案时,要输出字典序最小的...一开始忘了=号,结果答案错
	{
		ch = ( max(a, c) >= max(g, t) ? (a >= c? 'A':'C'):(g >= t? 'G' : 'T') );
		return max( max(a, c), max(g, t) );
	}
}dna[N];


int main()
{
	int t, m, n; //m是数目,n是长度
	cin >> t;
	while (t--)
	{
		int sum = 0;
		cin >> m >> n;
		for (int i = 0; i < n; i++)
			dna[i].clearall();//一定是按照位置清空的,也就是DNA长度,而不是DNA数
			
		for (int i = 0; i < m; i++)
		{
			cin >> check;
			for (int j = 0; j < n; j++)
			switch(check[j])
			{
				case'A': dna[j].a++;break;
				case'G': dna[j].g++;break;
				case'C': dna[j].c++;break;
				case'T': dna[j].t++;break;
			}
		}
		
		for (int i = 0; i < n; i++)
		{
			sum += m - dna[i].getmax(ans[i]);
		}
		ans[n] = '\0';
		
		cout << ans << endl << sum << endl;
		
	} 
	return 0;
}





posted @ 2017-08-25 14:14  mofushaohua  阅读(149)  评论(0编辑  收藏  举报