码迷,mamicode.com
首页 > 其他好文 > 详细

大连廿四2016暑假集训day1-T3(quick select&linear select)

时间:2016-08-06 21:56:12      阅读:386      评论:0      收藏:0      [点我收藏+]

标签:

3 kth
3.1 Description
给定 n 个不超过 10^9 的正整数,请线性时间选择算法 (linear select)求其中的第 k 大值。
3.2 Input
第一行两个整数 n,k。 第二行 n 个整数,表示题目中的那 n 个正整数。
3.3 Output
一行,表示答案。
3.4 Sample Input
10 3

2 4 7 3 5 6 9 6 1 8
3.5 Sample Output
7
3.6 Constraints
一共 10 个测试点,每个测试点 10 分,只有当你的答案与标准答案完全一致时才能得到 10 分,否则为 0 分。 对于 30% 的数据,n ≤ 1000。 对于 50% 的数据,n ≤ 100000。 对于 100% 的数据,1 ≤ n ≤ 106,1 ≤ k ≤ n。 时限制: 1s / 256M

 

被大神的linear select神到,自己今天又写了个quick select 一起贴上 %%%队长%%%w老师

linear select 的思想是把一个序列分成5个一组的区间,取每个区间的中位数,再取这些中位数中的中位数,有证明称其不小于区间1/4,不大于区间3/4,这样我们就缩小了问题规模,同时,求[中位数的中位数时]我们仍可以用到求区间第k大(小)数的算法,这样我们可以用上递归结构。

 1 //linear select O(100n)
 2 #include <stdio.h>
 3 #include <stdlib.h>
 4 
 5 const int MAXN = 1000005;
 6 
 7 int a[MAXN];
 8 
 9 int __cnt;
10 
11 inline void sort(int *a, int n) { //为了证明这个算法效率很高老师用了最慢的选择排序%%%
12     for (int i = 1; i < n; i++) {
13         for (int j = i + 1; j <= n; j++) {
14             ++__cnt;
15             if (a[i] > a[j]) {
16                 int tmp = a[i];
17                 a[i] = a[j];
18                 a[j] = tmp;
19             }
20         }
21     }
22 }
23 
24 int trivial_select(int *a, int n, int k) {//对一个区间排序,取中位数
25     sort(a, n);
26     return a[k];
27 }
28 
29 // a[]: 1-based
30 int select(int *a, int n, int k) {
31     static const int Q = 5;//区间的划分取奇数
32     if (n <= Q) {
33         return trivial_select(a, n, k);
34     }
35     int *b = new int[(n - 1) / Q + 1];
36     int c[Q];
37     int cnt = (n - 1) / Q + 1;
38     for (int i = 0; i < cnt; i++) {
39         for (int j = 0; j < Q; j++) {
40             c[j] = i * Q + j < n ? a[i * Q + j + 1] : 2147483647;
41         }
42         b[i] = trivial_select(c - 1, Q, (Q + 1) / 2);
43     }
44     int x = select(b - 1, cnt, (cnt + 1) / 2);//再划分区间中位数的中位数
45     delete []b;
46     
47     static int z[MAXN];
48     int l = 0, r = n + 1;
49     for (int i = 1; i <= n; i++) {
50         if (a[i] < x) {
51             z[++l] = a[i];
52         } else {
53             z[--r] = a[i];
54         }
55     }
56     for (int i = 1; i <= n; i++) {
57         a[i] = z[i];
58     }
59     if (k <= l) {
60         return select(a, l, k);
61     } else {
62         return select(a + l, n - l, k - l);
63     }
64 }
65 
66 int main() {
67     freopen("kth.in", "r", stdin);
68     freopen("kth.out", "w", stdout);
69     int n, k;
70     scanf("%d%d", &n, &k);
71     for (int i = 1; i <= n; i++) {
72         scanf("%d", a + i);
73     }
74     printf("%d\n", select(a, n, n - k + 1));
75 }

 

quick select的思路和快排类似,随机选择的数经历快排确定位置后,比它小的数都在它左边,比它大的数都在它右边,这样就可以缩小问题规模,递归出解,数据随机可以达到excepted O(nlogn)(常数未知)

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstdlib>
#include <ctime>
#define siji(i,x,y) for(int i=(x);i<=(y);i++)
#define gongzi(i,x,y) for(int j=(x);j>=y;j++)
#define maxn 1000005
#define random(x) (rand()%(x))
using namespace std;
int n,a[maxn],k;
int select(int l,int r)
{
    if(l==r) {return a[l];}
    int mid=random(r-l+1)+l;
    int key=a[mid];//mid为最终下标,不断检索,直到满足左边的都比key小,右边都比key大
    int first=l,last =r;
    while(first<last)
    {
        while(last>mid&&a[last]>=key)
        {
            last--;
        }
        swap(a[mid],a[last]);mid=last;//此时last指的数比mid小,可以拿mid与last交换
        while(first<mid&&a[first]<=key)
        {
            first++;
        }
        swap(a[first],a[mid]);mid=first;//此时first指的数比mid大,同上
    }
    if(k==mid) return a[mid];
    else if(k<mid)      return select(l,mid-1);//这里因为太弱出现了一个错误,就是没有写return……这可是一个int函数……真是太粗心了,不写的话会导致返回一个很大的野数
    else if (mid+1<=r) return select(mid+1,r);                                                                                                    
}
int main(int argc, char const *argv[])
{

    ios::sync_with_stdio(false);
    cin>>n>>k;
    siji(i,1,n) cin>>a[i];
    srand((int)time(0));//利用时间作为随机数种子
    cout<<select(1,n);
    return 0;
}

 

大连廿四2016暑假集训day1-T3(quick select&linear select)

标签:

原文地址:http://www.cnblogs.com/ivorysi/p/5744904.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!