题目1004:Median

来源:互联网 发布:软件演化生命周期模型 编辑:程序博客网 时间:2024/06/05 03:05
题目描述:

    Given an increasing sequence S of N integers, the median is the number at the middle position. For example, the median of S1={11, 12, 13, 14} is 12, and the median of S2={9, 10, 15, 16, 17} is 15. The median of two sequences is defined to be the median of the non-decreasing sequence which contains all the elements of both sequences. For example, the median of S1 and S2 is 13.
    Given two increasing sequences of integers, you are asked to find their median.

输入:

    Each input file may contain more than one test case.
    Each case occupies 2 lines, each gives the information of a sequence. For each sequence, the first positive integer N (≤1000000) is the size of that sequence. Then N integers follow, separated by a space.
    It is guaranteed that all the integers are in the range of long int.

输出:

    For each test case you should output the median of the two given sequences in a line.

样例输入:
4 11 12 13 145 9 10 15 16 17
样例输出:
13
来源:

2011年浙江大学计算机及软件工程研究生机试


题目很简单,因为两个字符串都是排序排好的,那么就可以用O(n)的算法直接合并了。

#include <iostream>#include <cstdio>#include <cstring>using namespace std;#define N 1000002int a[N],b[N],c[N*2];int main(){    int n1,n2,i,j,k;    while(scanf("%d",&n1)!=EOF)    {        for(i=0;i<n1;i++)            scanf("%d",&a[i]);        scanf("%d",&n2);        for(i=0;i<n2;i++)            scanf("%d",&b[i]);                    int n=n1+n2;        j=k=0;        for(i=0;j<n1&&k<n2;i++)        {            if(a[j]<b[k])            {                c[i]=a[j++];            }            else            {                c[i]=b[k++];            }        }        while(j<n1)        {            c[i++]=a[j++];        }            while(k<n2)        {            c[i++]=b[k++];        }                printf("%d\n",c[(n-1)/2]);    }    return 0;}

不过我后来发现了一个STL很神奇的函数nth_element

#include <algorithm>

nth_element作用为求第n小的元素,并把它放在第n位置上,下标是从0开始计数的,也就是说求第0小的元素就是最小的数。

#include "iostream"#include "algorithm"#include "string"using namespace std;long a[1000002];int main(){       long n1,n2,i,mid;        while(cin>>n1)        {              for(i=0;i<n1;i++)                   cin>>a[i];              cin>>n2;              for(;i<n1+n2;i++)                   cin>>a[i];              mid=(i-1)/2;              nth_element(a,a+mid,a+i);              cout<<a[mid]<<endl;         }    return 0;}

它的速度很快,不会对整体排序,对无序的字符串 也可以实现

具体的原理我在百度文库中找到,但是原作者已经不知道是谁了,

在这里请允许我转载过来。


nth_element 算法注解
nth_element 是 STL 提供的一个算法,用于找出序列中
的第 n 大元素。这个算法涉及下面4个辅助函数:
• _Nth_element
• _Unguarded_partition
• _Median
• _Med3

/*********************************************
**********************************************
*
_Nth_element
使序列中第 n 大的元素位于第 n 个位子上,使用 < 比
较元素。
基本思想:
(1) 找到一个包含 n 的足够小的区间[a,b),使得[a,b)
作为一个大粒度的元素处于序列的有序位置。
(2) 对[a,b)部分进行排序。
nth_element 查找区间的方式体现了二分(折半)查找的 思 想 。 它 的 核 心 是 ungarded_partition 算 法 ,
ungarded_partition 算法能够找出随机序列的近似的位
置中间值。
**********************************************
**********************************************
*/
template<class _RanIt> inline
void _Nth_element(_RanIt _First, _RanIt _Nth, _RanIt
_Last)
{ // order Nth element, using operator<
_DEBUG_RANGE(_First, _Last);
/* 逐步缩小[_First, _Last)的区间,直至尺寸小到可
以直接对局部进行排序。
_ISORT_MAX 是一个阀值,在<algorithm>中被定
义为32,表示适于插入法排序的序列的最大长度。*/
for (; _ISORT_MAX < _Last - _First; )
{ // divide and conquer, ordering partition containing
Nth
/* 把序列的当前部分划分为有序的三份。*/
pair<_RanIt, _RanIt> _Mid =_Unguarded_partition(_First, _Last);
/* 确定下一步搜索区间。*/
if (_Mid.second <= _Nth)
_First = _Mid.second;
else if (_Mid.first <= _Nth)
return; // Nth inside fat pivot, done
else
_Last = _Mid.first;
}
/* 对[_First, _Last)排序,第 n 大元素就到了第 n 个
位置上。*/
_Insertion_sort(_First, _Last); // sort any remainder
}
/*********************************************
**********************************************
*
_Unguarded_partition
把 序 列 划 分 为 有 序 的 三 份 : [_First, Mid.First),[Mid.First, Mid.Second), [Mid.Second, _Last) , 其 中
[Mid.First, Mid.Second)内的元素相等。
注意,不是等分:
(1) 不保证[Mid.First, Mid.Second )在位置上处于序列
的中间。
(2) 不保证[Mid.First, Mid.Second )在元素值上处于序
列的中间。
(3) [_First, Mid.First)和[Mid.Second, _Last)的长度有可
能为0。
(4) [_First, Mid.First) 中的 所 有 元 素 ( 若 有 ) 小 于
[Mid.First, Mid.Second )中的任一元素。 [Mid.Second,
_Last)中的则大于。
**********************************************
**********************************************
/
template<class _RanIt> inline
pair<_RanIt, _RanIt> _Unguarded_partition(_RanIt
_First, _RanIt _Last)
{ // partition [_First, _Last), using operator<
_RanIt _Mid = _First + (_Last - _First) / 2; // sort
median to _Mid/* 选择序列的位置平均值(近似),作为枢轴值
(pivot)。 */
_Median(_First, _Mid, _Last - 1);
/* [_Pfirst, _Plast) 就是要找的区间。*/
_RanIt _Pfirst = _Mid;
_RanIt _Plast = _Pfirst + 1;
/* 以枢轴值为起点,向序列的两头扫描,把相邻的
与枢轴值相等的元素合并到[_Pfirst, _Plast)中。
宏 _DEBUG_LT(x,y) 定义为 ((x)<(y))。
值得注意的是,下面的代码用两次 < 比较实现 ==
比较。*/
while (_First < _Pfirst
&& !_DEBUG_LT(*(_Pfirst - 1), *_Pfirst)
&& !(*_Pfirst < *(_Pfirst - 1)))
--_Pfirst;
while (_Plast < _Last
&& !_DEBUG_LT(*_Plast, *_Pfirst)
&& !(*_Pfirst < *_Plast))
++_Plast;/* 分别以[_Pfirst, _Plast)的起、止位置为起点,向
序列的两头扫描。*/
_RanIt _Gfirst = _Plast;
_RanIt _Glast = _Pfirst;
for (; ; )
{ // partition
for (; _Gfirst < _Last; ++_Gfirst)
if (_DEBUG_LT(*_Pfirst, *_Gfirst))
;
else if (*_Gfirst < *_Pfirst)
break;
else
std::iter_swap(_Plast++, _Gfirst);
/* 除非 _Gfirst == _Last,否则 *_Gfirst 应该调
到[_Pfirst, _Plast)的前面。*/
for (; _First < _Glast; --_Glast)
if (_DEBUG_LT(*(_Glast - 1), *_Pfirst))
;
else if (*_Pfirst < *(_Glast - 1))break;
else
std::iter_swap(--_Pfirst, _Glast - 1);
/* 除非 _Glast == _First,否则 *(_Glast-1) 应该
调到[_Pfirst, _Plast)的后面。*/
if (_Glast == _First && _Gfirst == _Last)
return (pair<_RanIt, _RanIt>(_Pfirst, _Plast));
/* 如果 *_Gfirst 和 *(_Glast-1) 都需要 调 到
[_Pfirst, _Plast)的对面,交换它俩就行了。
如果只有其中一个(记为 G)要调整,那就交换
它和[_Pfirst, _Plast)——实际上要复杂些,有两种情
况:
(1) G 与[_Pfirst, _Plast)相邻。这时只需要交换 G
和其对面的区间边界。
(2) G 与[_Pfirst, _Plast)之间有其它元素。这时需
要三方交换(两次):第一次交换使枢轴区间移动一个
单位(通过交换区间的内部边界和对面的外部边界来
实现),第二次交换完成调整任务。*/
if (_Glast == _First)
{ // no room at bottom, rotate pivot upwardif (_Plast != _Gfirst)
std::iter_swap(_Pfirst, _Plast);
++_Plast;
std::iter_swap(_Pfirst++, _Gfirst++);
}
else if (_Gfirst == _Last)
{ // no room at top, rotate pivot downward
if (--_Glast != --_Pfirst)
std::iter_swap(_Glast, _Pfirst);
std::iter_swap(_Pfirst, --_Plast);
}
else
std::iter_swap(_Gfirst++, --_Glast);
}
}
/*********************************************
**********************************************
_Median
找序列的近似位置平均值。
********************************************************************************************
/
template<class _RanIt> inline
void _Median(_RanIt _First, _RanIt _Mid, _RanIt _Last)
{ // sort median element to middle
if (40 < _Last - _First)
{ // median of nine
size_t _Step = (_Last - _First + 1) / 8;
_Med3(_First, _First + _Step, _First + 2 * _Step);
_Med3(_Mid - _Step, _Mid, _Mid + _Step);
_Med3(_Last - 2 * _Step, _Last - _Step, _Last);
_Med3(_First + _Step, _Mid, _Last - _Step);
}
else
_Med3(_First, _Mid, _Last);
}
/*********************************************
**********************************************
*
_Med3对三个元素排序。
**********************************************
**********************************************
/
template<class _RanIt> inline
void _Med3(_RanIt _First, _RanIt _Mid, _RanIt _Last)
{ // sort median of three elements to middle
if (_DEBUG_LT(*_Mid, *_First))
std::iter_swap(_Mid, _First);
if (_DEBUG_LT(*_Last, *_Mid))
std::iter_swap(_Last, _Mid);
if (_DEBUG_LT(*_Mid, *_First))
std::iter_swap(_Mid, _First);
}

0 0
原创粉丝点击