poj2299

排序后求交换次数,其实就是求逆序数。由于数据庞大,冒泡解决时间复杂度为O(n*n)会超时。所以用归并排序的方法时间复杂度降为O(n*logn)。

主要难点在于归并排序如何求逆序数, 在每次对2个有序集合进行merge时,当右边集合的elem[j]小于左边集合elem[i]时,则说明elem[j]小于左边集合

elem[i]---elem[mid]   mid-i+1个元素的值。则对于这个元素,它的逆序数即为mid-i+1。将所有右边集合元素的逆序数加起来就是总逆序数,再通过递归方法可以

求得总逆序数。(sum应该定义为全局变量,当时做的时候搞麻烦了 。。。O,o)

#include<iostream>
using namespace std;

long long Merge(int temp[],int elem[],int low,int mid,int high)//对于2个有序集合的排序和算逆序数方法
{
      int i,j,k;//临时变量,i为elem[low...mid]下标,j为elem[mid+1...high]下标,k为temp[]下标
      long long sum=0;//每次归并时右边集合每个元素的逆序数和
      for(i=low,j=mid+1,k=low;j<=high&&i<=mid;k++)//分别用2个下标走左右2个集合,小的就放到临时数组中
      {
            if(elem[i]<elem[j])
            {
                  temp[k]=elem[i];
                  i++;
            }
            else//如果右边集合下标为j的元素小一些,则由于2个集合均为有序的。所以j元素就比前面mid-i+1个元素小,即为逆序数
            {
                  temp[k]=elem[j];
                  j++;
                  sum+=mid-i+1;//通过递归将所有的逆序数相加
            }
      }
      for(;i<=mid;k++)//将剩余的元素放入临时数组中
      {
            temp[k]=elem[i++];
      }
      for(;j<=high;k++)
      {
            temp[k]=elem[j++];
      }
      for(i=low;i<=high;i++)//把临时数组拷贝到原数组中
      {
            elem[i]=temp[i];
      }
      return sum;
};

long long MergeHelp(int temp[],int elem[],int low,int high)//通过递归方法来排序求sum
{
      long long sum=0;
      if(low<high)
      {
            int mid=(low+high)/2;
            sum+=MergeHelp(temp,elem,low,mid);//左边集合排序
            sum+=MergeHelp(temp,elem,mid+1,high);//右边集合排序
            sum+=Merge(temp,elem,low,mid,high);//2个集合排序
      }
      return sum;
};

int main()
{
      int n;
      while(cin>>n&&n)
      {
            long long sum=0;
            int *elem=new int[n+2];
            int *temp=new int[n+2];
            for(int i=0;i<n;i++)
            cin>>elem[i];
            sum=MergeHelp(temp,elem,0,n-1);
            cout<<sum<<endl;
      }
      return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值