POJ 2442 Sequence (堆)

来源:互联网 发布:上海网络直播室 编辑:程序博客网 时间:2024/05/29 12:59

一道好题,利用堆求前N小和

题目给出m个长度为n数组,每个数组抽一个数字的和的前n小

算法描述:


sort(all data)

build_heap for data[0][0]+data[1][0], data[0][0]+data[1][1]......

for(i from 1 to end)

       for(j from 0 to end)

                    if(data[0][i]+data[1][j]<heap_top):

 heap_pop

                         heap_push(data[0][i]+data[1][j])

                     else :

                        break

sort heap

copy heap to data[0]


简单证明

当k=1时 堆为第一组数据排序,符合条件

设k=b时 符合条件,此时堆保存着前b组数据取和的n小值

当k=b+1时,前b+1组数据和的n小值必然等于第b+1组数据与堆之间和的n小值,因为如果有另一个组合+第b+1组某个数更小的话他必然出现在前b组数据和n小值之中

所以对所有正整数都满足

时间复杂度

首先先对读入的数列从小到大排序花费时间O(m*nlogn)

更新堆用了双重循环,所以更新heapO(n*nlogn)不过好像可以证明更新其实o(nlogn)不然排序就没意义了

sort heap nlgn

复制n

所以算法为O((m+n)*nlogn)



贴个代码,写的搓,手写的堆

#include <stdio.h>#include <stdlib.h>int data[101][2001];void heap(int now,int n,int data[]){int x=now,x1=now*2+1,x2=now*2+2;if(x1<n && data[x1]>data[x]){x=x1;}if(x2<n && data[x2]>data[x]){x=x2;}if(x!=now){data[x]^=data[now];data[now]^=data[x];data[x]^=data[now];heap(x,n,data);}}void make_heap(int n,int data[]){int i=n>>1;for(;i>=0;--i){heap(i,n,data);}return;}void sort_heap(int n,int data[2001]){int i=1,x=n-1;for(;i<n;++i){data[x]^=data[0];data[0]^=data[x];data[x]^=data[0];heap(0,x--,data);}}int cmp(const void *a,const void *b){return *(int *)a-*(int *)b;}void search(int m, int n){int tmp[2001],k=1,i=0,j=0;for(;k<m;++k){for(i=0;i<n;++i){tmp[i]=data[0][0]+data[k][i];}make_heap(n,tmp);for(i=1;i<n;++i){for(j=0;j<n && tmp[0]>data[0][i]+data[k][j];++j){tmp[0]=data[0][i]+data[k][j];heap(0,n,tmp);}}sort_heap(n,tmp);for(i=0;i<n;++i){data[0][i]=tmp[i];}}for(i=0;i<n;++i){printf("%d ",data[0][i]);}putchar('\n');return ;}int main(){int T,m,n,i,j;scanf("%d",&T);while(T--){scanf("%d %d",&m,&n);for(i=0;i<m;++i){for(j=0;j<n;++j){scanf("%d",&data[i][j]);}qsort(data[i],n,sizeof(int),cmp);}search(m,n);}}


原创粉丝点击