uva 11997 K Smallest Sums 优先队列

来源:互联网 发布:十大当红网络女作家 编辑:程序博客网 时间:2024/06/07 04:54

题目:https://uva.onlinejudge.org/external/119/11997.pdf



对于两组数a[n],b[n],每组长度为n,现在要得到a[i]+b[j] (1<=i,j<=n)的和   中前n小的值。

先对b[n]排序

方法是利用b[1] + x<b[2]+x<...<b[n]+x;

构造一个优先队列(小的优先)

先放入n个值 (a[1]+b[1]、a[2]+b[1]、a[3]+b[1]、......、a[n]+b[1]);

弄出n个指针p[i],分别表示队列里a[i]加上的是b[p[i] ];

每次取出队头,删去,然后补上一个新的元素。

比如取出 a[i]+b[p[i] ]

那么得到一个答案a[i]+b[p[i] ],然后放入a[i]+b[p[i] +1];

进行n次,那么可以得到前n小的数


变式:

对于两组数a[n],b[m],现在要得到a[i]+b[j] (1<=i<=n,1<=j<=m)的和   中前k小的值。

先对b[m]排序

方法是利用b[1] + x<b[2]+x<...b[m]+x;

构造一个优先队列(小的优先)

先放入n个值 (a[1]+b[1]、a[2]+b[1]、a[3]+b[1]、......、a[n]+b[1]);

弄出n个指针p[i],分别表示队列里a[i]加上的是b[p[i] ];

每次取出队头,删去,然后补上一个新的元素。

比如取出 a[i]+b[p[i] ]

那么得到一个答案a[i]+b[p[i] ],然后放入a[i]+b[p[i] +1];

进行k次,那么可以得到前k小的数


变式:

有n组数,每组数取一个数相加  得到一个结果,要求前k小的结果分别是多少。

对于每两组数,用到的一定是这两组数中(分别取1个数,他们的 和中)最小的k个数,

故将这两组变成了一组,减少了组数,依此类推,直到最后剩下一组(长度为k)


const int INF =0x3f3f3f3f;const int maxn= 760   ;//const int maxm=    ;//by yskysker123int n,a[maxn][maxn];int p[maxn];struct Node{    int num,index;    Node(){}    Node(int num,int index):num(num),index(index){}};struct cmp{    bool operator()(Node x,Node y   )    {        return x.num>y.num;    }};void merge(int le,int ri){    priority_queue<Node,vector<Node > ,cmp> q;    for(int i=1;i<=n;i++)    {        p[i]=1;        q.push(  Node( a[le][i]+a[ri][1],i)  );    }    for(int ii=1;ii<= n ;ii++)    {        Node tmp=q.top();q.pop();        int index=tmp.index;        int num=tmp.num;         a[le][ii]=num ;        p[index]++;        if(p[index]<=n  )        q.push(Node (num-a[ri][p[index]-1   ]+a[ri][p[index] ]  ,index   )   );    }}int main(){    int x;    while(~scanf("%d",&n))  //有一种错误叫做忘写~或!=EOF,这种错误常常是由于移动代码时造成的,通常还会在事先    {                       //表现为 () 内有;        for(int i=1;i<=n;i++)        {            for(int j=1;j<=n;j++)            {                scanf("%d",&a[i][j]);            }            sort(a[i]+1,a[i]+1+n);        }        for(int i=2;i<=n;i++)        {            merge(1,i );        }        for(int i=1;i<n ;i++)            printf("%d ",a[1][i]);        printf("%d\n",a[1][n]);    }    return 0;}


#include<cstdio>#include<string>#include<cstring>#include<iostream>#include<cmath>#include<algorithm>#include<climits>#include<queue>#include<vector>#include<map>#include<sstream>#include<set>#include<stack>#include<utility>#pragma comment(linker, "/STACK:102400000,102400000")#define PI 3.1415926535897932384626#define eps 1e-10#define sqr(x) ((x)*(x))#define FOR0(i,n)  for(int i=0 ;i<(n) ;i++)#define FOR1(i,n)  for(int i=1 ;i<=(n) ;i++)#define FORD(i,n)  for(int i=(n) ;i>=0 ;i--)#define  lson   num<<1,le,mid#define rson    num<<1|1,mid+1,ri#define MID   int mid=(le+ri)>>1#define zero(x)((x>0? x:-x)<1e-15)#define mk    make_pair#define _f     first#define _s     secondusing namespace std;//const int INF=    ;typedef long long ll;//const ll inf =1000000000000000;//1e15;//ifstream fin("input.txt");//ofstream fout("output.txt");//fin.close();//fout.close();//freopen("a.in","r",stdin);//freopen("a.out","w",stdout);


0 0
原创粉丝点击