1. 油井问题

发布时间:2023年12月21日

题干

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

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

?思路

????????BFPRT算法理论上很快(好像也不是很快,刚刚看到了一个博主的测试随机化快速排序+快速选择 复杂度证明+运行测试_快速选择复杂度证明-CSDN博客),实际嘛,也就一般般,测试了下在隐藏用例的数据集下(好像数据集不是很大),这并不是最快的方法。(我看报表里都有好多比这个快的,虽然没有超过0.01s的差距)

代码如下:

#include <iostream>
#include <fstream>
using namespace std;
// 插入排序
void InsertSort(int *a, int l, int r)
{
    int mid = (l + r) >> 1;
    for (int i = l + 1; i <= mid; ++i)
    {
        int x = a[i];
        int j = i - 1;
        while (j >= l && a[j] > x)
        {
            a[j + 1] = a[j];
            --j;
        }
        a[j + 1] = x;
    }
}
int BFPTR(int *a, int l, int r, int k);
int GetPovit(int *a, int l, int r)
{
    int x;
    int cnt = 0;
    // 将数组分为每组5个元素,并使用插入排序对每组进行排序
    for (x = l; x + 5 < r; x += 5)
    {
        InsertSort(a, x, x + 5);
        // 将每组的中位数与数组的最左元素进行交换
        swap(a[l + cnt], a[x + 2]);
        ++cnt;
    }
    // 对剩余的元素(小于5个)进行排序,并将中位数与数组的最左元素进行交换
    if (x < r)
    {
        InsertSort(a, x, r);
        swap(a[l + cnt], a[(x + r) >> 1]);
        ++cnt;
    }
    // 如果只有一个中位数,则返回其索引
    if (cnt == 1)
        return l;
    // 递归,找到中位数的"中位数"
    return BFPTR(a, l, l + cnt, cnt / 2);
}

int BFPTR(int *a, int l, int r, int k)
{
    // 当数组范围只有1个元素时,直接返回该元素的索引
    if (r - l == 1)
        return l;
    // 获取中轴元素的索引
    int idx = GetPovit(a, l, r);
    int povit = a[idx], i = l, j = r;
    // 将中轴元素与数组的最左元素交换
    swap(a[l], a[idx]);
    while (i < j)
    {
        do
            ++i;
        // 从左向右查找第一个大于等于中轴元素的元素
        while (i + 1 < r && a[i] < povit);
        do
            --j;
        // 从右向左查找第一个小于等于中轴元素的元素
        while (a[j] > povit);
        if (i < j)
            // 交换找到的两个元素,使较小的元素位于中轴元素的左侧,较大的元素位于右侧
            swap(a[i], a[j]);
    }
    swap(a[l], a[j]);
    int num = j - l + 1; // 中轴元素左侧的元素个数
    if (k == num)
        return j; // 如果中轴元素左侧的元素个数等于k,则中轴元素即为第k小的元素,返回其索引
    else if (num > k)
        return BFPTR(a, l, j, k); // 如果中轴元素左侧的元素个数大于k,则在左侧继续查找第k小的元素
    else
        return BFPTR(a, j + 1, r, k - num); // 如果中轴元素左侧的元素个数小于k,则在右侧继续查找第k-num小的元素
}

int main()
{
    int n = 1, x, a[200000] = {0};
    while (scanf("%d,%d", &x, &a[n]) != EOF)
        n++;
    int idx;
    idx = BFPTR(a, 1, n, n / 2);
    cout << a[idx] << endl;
    return 0;
}

文章来源:https://blog.csdn.net/Cosmo9/article/details/135128073
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。