题目要求的是一条DNA序列的逆序数,求逆序数可以考虑使用归并算法来进行求解。
我们来设想这样一个场景:相邻的A、B两块进行升序排序,各自都已经是排好序的了,且B排在A右边。那么当把B中的某数T放到已排序的数列中,那么A序列中剩下的数就是比数T要大的,但我们要注意到:在原序列中,由于B序列在A序列右边,那么对于“AB”块中,与数T对应的逆序数就是A序列中剩下的数量。
这便是用归并算法计算逆序数的精髓所在。
一个乱序序列的 逆序数 = 在只允许相邻两个元素交换的条件下,得到有序序列的交换次数
#include<iostream>
#include<algorithm>
using namespace std;
int number = 0;
typedef class dna
{
public:
int num; //逆序数
char sq[110]; //DNA序列
string sq_bankend;
}DNAStr;
void Merge(char* r,char* r1,int s,int m, int t)
{
int i = s;
int j = m+1;
int k = s;
while(i<=m && j<=t)
{
if(r[i] <= r[j] )
r1[k++] = r[i++];
else
{
number += m-i+1; //用来统计逆序数
r1[k++] = r[j++];
}
}
if( i<=m)
while(i<=m)
r1[k++] = r[i++];
else
while(j<=t)
r1[k++] = r[j++];
return;
}
void MergePass(char* r,char* r1,int n,int h)
{
int i=0;
int k;
while(i<=n-2*h)
{
Merge(r,r1,i,i+h-1,i+2*h-1);
i += 2*h;
}
if(i<n-h) Merge(r,r1,i,i+h-1,n-1);
else
for(k = i;k<n;k++)
r1[k] = r[k];
}
int MergeSort(char* r ,int n)
{
int h =1;
char *r1 = (char*)malloc(sizeof(char) * n);
while(h<n)
{
MergePass(r,r1,n,h);
h = 2*h;
MergePass(r1,r,n,h);
h = 2*h;
}
free(r1);
return number;
}
int cmp(const void* a,const void* b)
{
DNAStr* x=(DNAStr*)a;
DNAStr* y=(DNAStr*)b;
return (x->num)-(y->num);
}
int main()
{
int n,m;
while(cin>>n>>m)
{
DNAStr* DNA=new DNAStr[m];
for(int i=0;i<m;i++)
{
cin>>DNA[i].sq;
DNA[i].sq_bankend = DNA[i].sq;
DNA[i].num = MergeSort(DNA[i].sq,n);
number = 0;
}
qsort(DNA,m,sizeof(DNAStr),cmp);
for(int j=0;j<m;j++)
cout<<DNA[j].sq_bankend.c_str()<<endl;
}
return 0;
}