• 实验6选第k小元素:特定分治策略


    问题:

    给出一个数组$a[n]$,求第$k$小元素是什么。

    解析:

    分治思想,将数组五个一组划分,并计算出每组数的中位数。然后把各组中位数的中位数找出。统计数组中小于中位数的个数$num$,有三种情况。

    ①    $num = k$,则中位数就是要查询的数。

    ②    $num > k$,则在小于中位数的集合中查询第$k$小。

    ③    $num < k$,则在大于中位数的集合中查询第$k – num$小。

    设计(核心代码):

     1 void insertsort(int a[], int l, int r)//从小到大排序
     2 {
     3     int i, j, key;
     4     for (i = l + 1; i <= r; ++i)
     5     {
     6         key = a[i];
     7         for (j = i - 1; j >= l && key < a[j]; --j)
     8         {
     9             a[j + 1] = a[j];
    10         }
    11         a[j + 1] = key;
    12     }
    13 }
    14 
    15 int partition(int a[], int l, int r, int pivot)
    16 {
    17     int x, i = l - 1, j;
    18     for (j = l; j < r; ++j)
    19     {
    20         if (a[j] == pivot)    swap(a[j], a[r]);
    21     }
    22     x = a[r];
    23     for (j = l; j < r; ++j)
    24     {
    25         if (a[j] <= x)
    26         {
    27             ++i;
    28             swap(a[i], a[j]);
    29         }
    30     }
    31     swap(a[r], a[i + 1]);
    32     return i + 1;
    33 }
    34 
    35 int select(int a[], int l, int r, int k)
    36 {
    37     int group, i, left, right, mid;
    38     int pivot, p, lnum;
    39     if (r - l + 1 <= 5)
    40     {
    41         insertsort(a, l, r);
    42         return a[l + k - 1];
    43     }
    44     group = (r - l + 1 + 5) / 5;
    45     for (i = 0; i < group; ++i)
    46     {
    47         left = l + 5 * i;
    48         right = (l + 5 * i + 4) > r ? r : l + 5 * i + 4;
    49         mid = (left + right) / 2;
    50         insertsort(a, left, right);
    51         swap(a[l + i], a[mid]);
    52     }
    53     pivot = select(a, l, l + group - 1, (group + 1) / 2);
    54     p = partition(a, l, r, pivot);
    55     lnum = p - l;
    56     if (k == lnum + 1)
    57         return a[p];
    58     else if (k <= lnum)
    59         return select(a, l, p - 1, k);
    60     else
    61         return select(a, p + 1, r, k - lnum - 1);
    62 }

    分析:

    复杂度:$O(n)$。

    源码:

    https://github.com/Big-Kelly/Algorithm

      1 #include<bits/stdc++.h>
      2 #include <set>
      3 #include <map>
      4 #include <stack>
      5 #include <cmath>
      6 #include <queue>
      7 #include <cstdio>
      8 #include <string>
      9 #include <vector>
     10 #include <cstring>
     11 #include <iostream>
     12 #include <algorithm>
     13 
     14 #define ll long long
     15 #define pll pair<ll,ll>
     16 #define pii pair<int,int>
     17 #define bug printf("*********
    ")
     18 #define FIN freopen("input.txt","r",stdin);
     19 #define FON freopen("output.txt","w+",stdout);
     20 #define IO ios::sync_with_stdio(false),cin.tie(0)
     21 #define ls root<<1
     22 #define rs root<<1|1
     23 #define Q(a) cout<<a<<endl
     24 
     25 using namespace std;
     26 const int inf = 2e9 + 7;
     27 const ll Inf = 1e18 + 7;
     28 const int maxn = 1e6 + 5;
     29 const int mod = 1e9 + 7;
     30 
     31 ll gcd(ll a, ll b)
     32 {
     33     return b ? gcd(b, a % b) : a;
     34 }
     35 
     36 ll lcm(ll a, ll b)
     37 {
     38     return a / gcd(a, b) * b;
     39 }
     40 
     41 ll read()
     42 {
     43     ll p = 0, sum = 0;
     44     char ch;
     45     ch = getchar();
     46     while (1)
     47     {
     48         if (ch == '-' || (ch >= '0' && ch <= '9'))
     49             break;
     50         ch = getchar();
     51     }
     52 
     53     if (ch == '-')
     54     {
     55         p = 1;
     56         ch = getchar();
     57     }
     58     while (ch >= '0' && ch <= '9')
     59     {
     60         sum = sum * 10 + ch - '0';
     61         ch = getchar();
     62     }
     63     return p ? -sum : sum;
     64 }
     65 
     66 void insertsort(int a[], int l, int r)//从小到大排序
     67 {
     68     int i, j, key;
     69     for (i = l + 1; i <= r; ++i)
     70     {
     71         key = a[i];
     72         for (j = i - 1; j >= l && key < a[j]; --j)
     73         {
     74             a[j + 1] = a[j];
     75         }
     76         a[j + 1] = key;
     77     }
     78 }
     79 
     80 int partition(int a[], int l, int r, int pivot)
     81 {
     82     int x, i = l - 1, j;
     83     for (j = l; j < r; ++j)
     84     {
     85         if (a[j] == pivot)    swap(a[j], a[r]);
     86     }
     87     x = a[r];
     88     for (j = l; j < r; ++j)
     89     {
     90         if (a[j] <= x)
     91         {
     92             ++i;
     93             swap(a[i], a[j]);
     94         }
     95     }
     96     swap(a[r], a[i + 1]);
     97     return i + 1;
     98 }
     99 
    100 int select(int a[], int l, int r, int k)
    101 {
    102     int group, i, left, right, mid;
    103     int pivot, p, lnum;
    104     if (r - l + 1 <= 5)
    105     {
    106         insertsort(a, l, r);
    107         return a[l + k - 1];
    108     }
    109     group = (r - l + 1 + 5) / 5;
    110     for (i = 0; i < group; ++i)
    111     {
    112         left = l + 5 * i;
    113         right = (l + 5 * i + 4) > r ? r : l + 5 * i + 4;
    114         mid = (left + right) / 2;
    115         insertsort(a, left, right);
    116         swap(a[l + i], a[mid]);
    117     }
    118     pivot = select(a, l, l + group - 1, (group + 1) / 2);
    119     p = partition(a, l, r, pivot);
    120     lnum = p - l;
    121     if (k == lnum + 1)
    122         return a[p];
    123     else if (k <= lnum)
    124         return select(a, l, p - 1, k);
    125     else
    126         return select(a, p + 1, r, k - lnum - 1);
    127 }
    128 
    129 int a[maxn];
    130 int n, k;
    131 
    132 int main()
    133 {
    134     scanf("%d %d", &n, &k);
    135     for (int i = 1; i <= n; ++i)    scanf("%d", &a[i]);
    136     printf("%d
    ", select(a, 1, n, k));
    137 }
    View Code
  • 相关阅读:
    洛谷 P1692 部落卫队
    洛谷 P1113 杂务
    洛谷 P1546 最短网络 Agri-Net
    洛谷 P2121 拆地毯
    洛谷 P2728 纺车的轮子 Spinning Wheels
    洛谷 P2126 Mzc家中的男家丁
    线段树双标记——乘法和加法
    A. Feed the cat
    洛谷 P1535 游荡的奶牛
    BZOJ1050 [HAOI2006]旅行
  • 原文地址:https://www.cnblogs.com/zhang-Kelly/p/12656365.html
Copyright © 2020-2023  润新知