NYOJ 634万里挑一(优先队列)

题目连接: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\n",C[i]);
52     }
53     return 0;
54 }

 



posted @ 2013-07-18 16:21  SStep  阅读(300)  评论(0编辑  收藏  举报