poj-1007

//428K  0MS G++ mergeSort
#include <cstdio>
#include <cstring>
#include <cstdlib>

char str1[110];
char str2[110];

char tmp1[110];
char tmp2[110];

char strs[110][110];

struct StrInfo{
    int reverseOrderNum;
    int pos;
} strInfos[110];

typedef struct StrInfo StrInfo;

int comp(const void * a,const void * b) {
    return (*(StrInfo*)a).reverseOrderNum
            - (*(StrInfo*)b).reverseOrderNum;
}

int MergeSort(char * array, int begin, int end) {
    // printf("%d %d\n", begin ,end);
    if (begin == end) {
        return 0;
    }
    int totalReverseOrderNum = 0;
    int mid = (begin + end)>>1;
    int leftPartReverseOrderNum = MergeSort(array, begin, mid);
    int rightPartReverseOrderNum = MergeSort(array, mid + 1, end);
    totalReverseOrderNum += leftPartReverseOrderNum;
    totalReverseOrderNum += rightPartReverseOrderNum;

    memset(tmp1, 0, sizeof(tmp1));
    memset(tmp2, 0, sizeof(tmp2));

    // printf("P1 %d %d\n", mid - begin + 1, end - (mid + 1) + 1);
    memcpy(tmp1, array + begin, mid - begin + 1);
    memcpy(tmp2, array + mid + 1, end - (mid + 1) + 1);

    // printf("STR1: %s STR2: %s\n", tmp1, tmp2);

    int leftIndex = 0;
    int rightIndex = 0;
    int index = begin;
    while(tmp1[leftIndex] && tmp2[rightIndex]) {
        if (tmp1[leftIndex] <= tmp2[rightIndex]) {
            // printf("%c < %c\n", tmp1[leftIndex], tmp2[rightIndex]);
            array[index] = tmp1[leftIndex];
            leftIndex++;
        } else {
            array[index] = tmp2[rightIndex];
                // printf("%c >= %c %d %d\n", tmp1[leftIndex], tmp2[rightIndex], leftIndex, rightIndex);
            totalReverseOrderNum += mid - begin + 1 - leftIndex;
            rightIndex++;
        }
        index++;
    }


    while(tmp1[leftIndex]) {
        array[index++] = tmp1[leftIndex++];
    }

    while(tmp2[rightIndex]) {
        array[index++] = tmp2[rightIndex++];
    }

    // memset(tmp1, 0, sizeof(tmp1));
    // memcpy(tmp1, array + begin, end - begin + 1);
    // printf("FINAL: %s\n", tmp1);
    return totalReverseOrderNum;
}

int InversionNumber(char* s, int len)  
{  
    int ans=0;  //s逆序数  
    int A,C,G;  //各个字母出现次数,T是最大的,无需计算T出现次数  
    A=C=G=0;  
    for(int i=len-1;i>=0;i--)  
    {  
        switch(s[i])  
        {  
            case 'A':A++;break;  //A是最小的,无逆序数  
            case 'C':  
                 {  
                     C++;  
                     ans+=A;  //当前C后面出现A的次数就是这个C的逆序数  
                     break;  
                 }  
            case 'G':  
                {  
                    G++;  
                    ans+=A;  
                    ans+=C;  
                    break;  
                }  
            case 'T':  
                {  
                    ans+=A;  
                    ans+=C;  
                    ans+=G;  
                    break;  
                }  
        }  
    }  
    return ans;  
}  

int getReverseOrderNum(char * str) {
    memcpy(str2, str, strlen(str) + 1);
    // printf("%s\n", str2);
    int res = MergeSort(str2, 0, strlen(str2) - 1);
    // printf("%s\n", str2);
    // int res = InversionNumber(str2, strlen(str2));
    return res; 
}

int length;
int strNum;

int main() {

    while(scanf("%d %d", &length, &strNum) != EOF) {
        for (int i = 0; i < strNum; i++) {
            scanf("%s", strs[i]);
            strInfos[i].pos = i;
            strInfos[i].reverseOrderNum = getReverseOrderNum(strs[i]);
            // strInfos[i].reverseOrderNum = InversionNumber(strs[i], strlen(strs[i]));
            // printf("%d\n", strInfos[i].reverseOrderNum);
        }

        qsort(strInfos, strNum, sizeof(StrInfo), comp);

        for (int i = 0; i < strNum; i++) {
            printf("%s\n", strs[strInfos[i].pos]);
        }
    }
}


MLGB,strInfos数组开小了,WA了好几次

算是一道很好的基础题,因为这道题可以是归并排序和快速排序的综合题,

首先要用归并排序(也可以树状数组,线段树,不过归并最接地气)求出每个字符串的逆序数(在这里犯了好多细节错误,以后要好好理理, 并且因为本题的特殊性,只有四种字母,因此可以用o(n)方法来求,写起来简单些,虽然不算快), 然后就是快速排序(不想写了,直接qsort)将逆序数俺从小到大排,输出对应的字符串就可以。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值