<数据结构学习>排序——找第k小的元素问题

问题描述

主油管道为东西向,确定主油管道的南北位置,使南北向油井喷油管道和最小。要求线性时间完成。

1<= 油井数量 <=2 000 000

输入要求:

输入有油井数量行,第 K 行为第 K 油井的坐标 X ,Y 。其中, 0<=X<2^31,0<=Y<2^31 。

输出要求:

输出有一行, N 为主管道最优位置的最小值

注意:用快排做的不给分!!

友情提示:可以采用while(scanf("%d,%d",&x,&y) != EOF)的数据读入方式。

测试输入期待的输出时间限制内存限制额外进程
测试用例 1以文本方式显示
  1. 41,969978↵
  2. 26500,413356↵
  3. 11478,550396↵
  4. 24464,567225↵
  5. 23281,613747↵
  6. 491,766290↵
  7. 4827,77476↵
  8. 14604,597006↵
  9. 292,706822↵
  10. 18716,289610↵
  11. 5447,914746↵
以文本方式显示
  1. 597006↵
1秒64M0

问题分析

由于本篇参考的博客写的真的很全很好很易懂,所以在此不再赘述,详情请看参考博客。 

问题解决

#include <iostream>
#include <algorithm>
#define N 2000020
using namespace std;
long long y[N],cc=0;
void change(long long a[],long long x,long long y) 
{
    long long tt;
    tt=a[x];
    a[x]=a[y];
    a[y]=tt;
}

void Insert(long long a[],long long begin,long long end) //直接插入排序
{
    for(long long i=begin;i<=end;i++)
    {
        long long t=a[i];
        long long mark=i;
        if(a[i]<a[i-1]&&i>=begin+1)
        {
            while(a[mark-1]>t)
            {
                a[mark]=a[mark-1];
                mark--;
            }
            a[mark]=t;
        }
    }
}

long long Middle(long long a[],long long b,long long e)
{
    long long count=0,i;
    for(i=b;i+4<=e;i+=5)
    {
        Insert(a,i,i+4);
        change(a,b+count,i+2); //把中位数换到前面
        count++;
    }
    if(i<e) //剩余够不了一组的元素
    {
        Insert(a,i,e);
        change(a,b+count,(i+e)/2);
        count++;
    }

    if(count<=1) return a[b]; //递归出口,组内元素个数很少时,中位数近似取第一个
    return Middle(a,b,b+count-1);//递归调用
}

long long Index(long long a[],long long b,long long e,long long o)
{
    for(long long i=b;i<e;i++)
    {
        if(a[i]==o)
        return i;
    }
}

long long Part(long long a[],long long b,long long e,long long obj)
{
    long long loc=Index(a,b,e,obj);
    change(a,loc,e);//把中位数换到最后一个位置
    long long tt=a[e];
    long long i=b,j=e-1;
    while(i<j)
    {
        while(a[i]<tt) i++;
        while(a[j]>tt) j--;
        if(i<j) change(a,i,j);
    }
    //if(a[i]<tt) return e; //一定注意:单独考虑所有数都比中位数小的情况,不需要和最后一个交换

    change(a,i,e);
    return i;
}

long long Findlittle(long long a[],long long b,long long e,long long little)
{
    long long mm=Middle(a,b,e);
    long long site=Part(a,b,e,mm);
    long long n = site-b+1;
    if(n==little) return mm;
    else if(little<n) return Findlittle(a,b,site-1,little);
    else return Findlittle(a,site+1,e,little-n);
}


int main()
{
    long long xi,yi;
    while(scanf("%lld,%lld",&xi,&yi) != EOF)
    {
        y[cc++]=yi;
    }
    long long res=Findlittle(y,0,cc-1,(cc+1)/2);
    cout<<res<<endl;

    return 0;
}

参考博客

递归与分治 | 1:选择算法/中位数 —— 例题:油井

  • 10
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值