Online Judge | Problem Set | Authors | Online Contests | User | ||||||
---|---|---|---|---|---|---|---|---|---|---|
Web Board Home Page F.A.Qs Statistical Charts | Current Contest Past Contests Scheduled Contests Award Contest |
终于AC了!内含代码及注释~~#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; typedef struct CElement{ int sum,pos; }CElement; int data[2][2001]; int a2b[2001]; CElement minHeap[2001]; //自己写的堆,测试发现比stl的优先队列要快那么100多ms……囧…… void add(int sum,int pos){ int hole=(++minHeap[0].sum); while(hole!=1 && minHeap[hole/2].sum>sum){ minHeap[hole]=minHeap[hole/2]; hole/=2; } minHeap[hole].sum=sum; minHeap[hole].pos=pos; } CElement popMin(){ CElement ret; if(minHeap[0].sum)ret=minHeap[1]; CElement tmp=minHeap[minHeap[0].sum--]; int pa=1,child; while(pa*2<=minHeap[0].sum){ child=pa*2; if(child+1<=minHeap[0].sum && minHeap[child+1].sum<minHeap[child].sum)child++; if(minHeap[child].sum<tmp.sum){ minHeap[pa]=minHeap[child]; pa=child; } else break; } minHeap[pa]=tmp; return ret; } //此处是算法的核心,求数组a和b的两两之和的前n小元素,放入数组c中。 //用一个额外数组a2b保留a与b数组元素的映射关系,例如a2b[1]=1,指的是a数组第一个元素将于b数组第一个元素求和。每次从堆里弹出一个元素,就要将相应的a2b自增1,求和后再放入堆中,同时根据a2b是否为1判断是否要添加下一个元素。初始数组是有序的,这样就保证每次添加的元素都是当前可能的最小和。这样,每次最多求2次和,一共有n次,故将求和运算这一块的复杂度从O(n^2)降为O(2n) void nMinSum(int a[],int b[],int c[],int len){ int count=0; CElement tmp; memset(a2b,0,sizeof(a2b)); memset(minHeap,0,sizeof(minHeap)); a2b[1]=1; add(a[1]+b[1],1); while(count!=len){ tmp=popMin(); c[++count]=tmp.sum; if(count==len)break; if(a2b[tmp.pos]==1){ a2b[tmp.pos+1]=1; add(a[tmp.pos+1]+b[1],tmp.pos+1); } a2b[tmp.pos]++; add(a[tmp.pos]+b[a2b[tmp.pos]],tmp.pos); } } int main(){ //freopen("in.txt","r",stdin); int T,m,n; int i,j; int sum[2001]; scanf("%d",&T); while(T--){ memset(data,0,sizeof(data)); memset(sum,0,sizeof(sum)); scanf("%d %d",&m,&n); for(i=0;i<m;i++){ for(j=1;j<=n;j++){ scanf("%d",&data[i%2][j]); } sort(data[i%2]+1,data[i%2]+n+1); if(i!=0){ if(i%2)nMinSum(data[i%2-1],data[i%2],sum,n); else nMinSum(data[i%2+1],data[i%2],sum,n); for(j=1;j<=n;j++)data[i%2][j]=sum[j]; } } i=(i-1)%2; for(j=1;j<=n;j++)printf("%d ",data[i][j]);//此处一定要注意!考虑到m=1的情形,不能直接打印sum数组,而是要打印data[m-1]数组。正是在此处白白贡献了十多次WA!!! printf("\n"); } return 0; } Followed by:
Post your reply here: |
All Rights Reserved 2003-2013 Ying Fuchen,Xu Pengcheng,Xie Di
Any problem, Please Contact Administrator