题目连接:http://acm.nyist.net/JudgeOnline/problem.php?pid=634
分别从两个数组中各任取一个数相加,可以得到n^2个和,求这些和中最大的前m个数;
我们把这n^2个和组织成如下n个有序表:
表1:A1+B1 >= A1+B2 >= A1+B3 >= ........
表2;A2+B1 >= A2+B2 >= A2+B3 >=.......
表3:An+B1 >= An+B2 >= An +B3 >=......
其中第a张表里的元素形如Aa+Bb,我们用二元组(s,b)来表示一个元素,其中s=Aa+Bb.
为什么不保存A的下表a呢?因为我们用不到a的值。如果我们需要得到一个元素(s,b)在表a中的下一个元素(s1,b+1),只需要计算s1 =Aa+Bb+1=Aa+Bb-Bb+Bb+1=s-Bb+Bb+1,并不需要知道a是多少.
对于上边n个有序表,我们要找前m大的的数,先在第一列找出第一个大的数,然后去掉,并用它的下一个元素补上,再在第一列找出一个最大的数,重复此动作就可以到得前m大的数;在程序里用优先队列保存第一列n个元素。
1 #include<queue> 2 #include<cstdio> 3 #include<algorithm> 4 using namespace std; 5 #define N 110012 6 int A[N],B[N],C[N]; 7 bool cmp(int a,int b) 8 { 9 return a > b; 10 } 11 12 struct Item 13 { 14 int s,b; 15 Item(int s=0,int b=0):s(s),b(b) {} 16 bool operator <(const Item & a)const 17 { 18 return s < a.s;//按s的大小从大到小排序 19 } 20 }; 21 int main() 22 { 23 //freopen("in.txt","r",stdin); 24 int i,n,m; 25 Item item; 26 while(scanf("%d%d",&n,&m) != EOF) 27 { 28 priority_queue<Item> q;//定义一个对象为结构体的优先队列 29 for(i=0; i<n; i++) 30 scanf("%d",&A[i]); 31 for(i=0; i<n; i++) 32 scanf("%d",&B[i]); 33 34 sort(A,A+n,cmp); 35 sort(B,B+n,cmp);//数组元素从大到小排序 36 37 for(i=0; i<m; i++) 38 q.push(Item(A[i] + B[0], 0));//保存n个元素 39 40 for(i=0; i<m; i++) 41 { 42 item = q.top(); 43 q.pop(); 44 C[i] = item.s; 45 int b = item.b; 46 if(b+1 < n) 47 q.push(Item(item.s - B[b]+B[b+1],b+1));//把刚去掉元素的下一个元素加入队列中(同一张表的下一个元素) 48 } 49 for(i=m-1; i; i--) 50 printf("%d ",C[i]); 51 printf("%d ",C[i]); 52 } 53 return 0; 54 }