POJ 1007 – DNA Sorting
试题链接:POJ 1007
测试数据:1998 ACM East Central Programming Contest
本题事实上要求一个数组的逆序对个数。所为数组 a [ 1.. n ] a[1..n] a[1..n]的逆序对,就是对于 1 ≤ i , j ≤ n 1 \le i, j \le n 1≤i,j≤n,若 i < j i < j i<j且 a [ i ] > a [ j ] a[i] > a[j] a[i]>a[j],则称 a [ i ] a[i] a[i]和 a [ j ] a[j] a[j]互为一组逆序对。
我们可以通过修改归并排序(MergeSort)的程序,计算数组中的逆序对个数,时间复杂度仅为 O ( n lg n ) O(n\lg n) O(nlgn)。算法描述如下:
int mergeAndCount(A[low..high])
{
cnt = 0; // number of inversions
mid = (low + high) / 2;
temp = []; // store sorted array
i = low; // left: A[low..mid]
j = mid + 1; // right: A[mid+1..high]
while (i <= mid && j <= high)
{
if (A[i] <= A[j]) // no inversion
temp.append(A[i++]);
else // A[i..mid] > A[j], has (mid-i+1) inv's
{
temp.append(A[j++]);
cnt += (mid-i+1);
}
}
// copy down the rest
while (i <= mid) temp.append(A[i++]);
while (j <= high) temp.append(A[j++]);
// assign a sorted array
A[low..high] = temp;
return cnt;
}
int sortAndCount(A[low..high])
{
if (low == high)
return 0; // recursion exit
cnt = 0; // number of inversions
mid = (low + high) / 2;
cnt += sortAndCount(A[low..mid]); // left part, after that A[low..mid] is sorted
cnt += sortAndCount(A[mid+1..high]); // right part, after that A[mid+1..high] is sorted
cnt += mergeAndCount(A[low..high]); // between, after that A[low..high] is sorted
return cnt;
}
Call: sortAndCount(A[1..n])
代码如下:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>
#define MAX_LENGTH 52
struct Sequence
{
char seq[MAX_LENGTH];
int unsorted;
};
bool cmp (const Sequence &a, const Sequence &b)
{
return a.unsorted < b.unsorted;
}
int merge_get_inversions(Sequence *sequence, int low, int mid, int high)
{
int cnt = 0;
char *tmp = (char *)malloc(sizeof(char) * (high-low+1));
int i = low;
int j = mid + 1;
int k = 0;
while (i <= mid && j <= high)
{
if (sequence->seq[i] <= sequence->seq[j])
tmp[k++] = sequence->seq[i++];
else
{
tmp[k++] = sequence->seq[j++];
cnt += (mid - i + 1);
}
}
while (i <= mid)
tmp[k++] = sequence->seq[i++];
while (j <= high)
tmp[k++] = sequence->seq[j++];
for (i = low; i <= high; ++i)
sequence->seq[i] = tmp[i-low];
free(tmp);
return cnt;
}
int get_inversions(Sequence *sequence, int low, int high)
{
if (low >= high)
return 0;
int cnt = 0;
int mid = (low + high) / 2;
cnt += get_inversions(sequence, low, mid);
cnt += get_inversions(sequence, mid+1, high);
cnt += merge_get_inversions(sequence, low, mid, high);
return cnt;
}
int main()
{
int n, m;
Sequence *sequences;
scanf("%d %d", &n, &m);
sequences = (Sequence *)malloc(sizeof(Sequence) * m);
for (int i = 0; i < m; ++i)
{
char tmp[MAX_LENGTH] = {'\0'};
scanf("%s", sequences[i].seq);
strcpy(tmp, sequences[i].seq);
sequences[i].unsorted = get_inversions(&sequences[i], 0, n-1);
strcpy(sequences[i].seq, tmp);
}
std::stable_sort(sequences, sequences+m, cmp);
for (int i = 0; i < m; ++i)
printf("%s\n", sequences[i].seq);
return 0;
}