【UVA11997】K Smallest Sums

来源:互联网 发布:于右任书法 知乎 编辑:程序博客网 时间:2024/06/05 01:15

题意

  有n个序列,每个序列有n个元素。现在要在每个序列里选一个元素出来,求元素总和前n小的值

解法

优先队列:
  最简单的想法就是直接枚举所有可能的方案,然后排序求出前n小的方案
  我们用一个n元组来表示一种组合
  首先我们把每个序列从小到大排好序,那么最小的组合就是(1,1,…,1)了,至于第二小,在某个序列里选大一点……形式化地,就是给某个加1,第二小的选择就是在这些待选的组合里总花费最小的。一般地,我们在所有待选组合里选出一个花费最小的,把它踢出待选组合,再把它的某个加1后放入待选组合中。
  选出花费最小的不就是优先队列的工作么?用优先队列来优化取最小值和插入就可以了

复杂度

O(nlogn

代码

#include<algorithm>#include<iostream>#include<cstdlib>#include<cstdio>#include<queue>#define Rint register int#define Lint long long intusing namespace std;const int N=1010;struct node{    int s,x;    bool operator < (const node &a) const    {        return s>a.s;    }};int w[N][N];int n;priority_queue<node> q;int main(){    int x;    node tmp;    while( scanf("%d",&n)!=EOF )    {        for(int i=1;i<=n;i++)        {            for(int j=1;j<=n;j++)   scanf("%d",&w[i][j]);            sort( w[i]+1,w[i]+n+1 );        }        for(int i=2;i<=n;i++)        {            while( !q.empty() )   q.pop();            for(int j=1;j<=n;j++)                q.push( (node){ w[1][j]+w[i][1],1 } );            for(int j=1;j<=n;j++)            {                tmp=q.top(),q.pop();                w[1][j]=tmp.s,x=tmp.x;                if( x<n )                {                    tmp.s=tmp.s-w[i][x]+w[i][x+1];                    tmp.x=x+1;                    q.push( tmp );                }            }        }        for(int i=1;i<=n;i++)        {            printf("%d",w[1][i]);            if( i!=n )   printf(" ");        }        printf("\n");    }    return 0;}