UVa - 11997 K Smallest Sums(优先队列多路归并)

来源:互联网 发布:家里wifi有信号没网络 编辑:程序博客网 时间:2024/06/03 15:44


题意是k个数组,每个数组k个元素,每个数组取一个元素,共k个数之和成为一个参考值,求出k^k个参考值中最小的k个    ...


方法就是先 对每个数组排序,    然后由于k个之和最小和 2个之和最小是一样的,那么每次处理两个数组就可以了。。。。


对数组A,B  求前k小的A[i]+B[i]   

方法是不断取尽可能小的放到优先队列,然后直接取前K个就行了

第一次我的取法是: 

node t=优先队列.top();

优先队列.pop();

//把最接近t的两个和存进去 

if (t.x+1<=n  )    
Q.push(node(t.x+1,t.y,A[t.x+1]+B[t.y])); 
if (t.y+1<=m)
Q.push(node(t.x,t.y+1,A[t.x]+B[t.y+1]));
  

 // 严重错误之处,这样不断插入最临近的两个点会造成一个问题,就是会重复!意思是
//例如A+B已经插入过了。他们是A-1,B的临近点,但是在A,B-1的时候,A+B又被插入了一次,这样就会导
// 致结果变化,因此应该改。

// 正确方法是,先把全部A[i]+B[1]插入,再不断插入B【i】才能不重复!!

然后重复k-1次就可以了


#include <cstdio>#include <cmath>#include <cstring>#include <string>#include <algorithm>#include <iostream>#include <queue>#include <map>#include <set>#include <vector>using namespace std; int k;int tm[800][800];struct node{int a,b,s;node (){}node (int x,int y,int v){a=x,b=y,s=v;}bool operator<( const node& b) const{return s>b.s;}};void  merge(int a[],int b[]){priority_queue <node> qq;  //while(!qq.empty())qq.pop();int i,j;for (i=1;i<=k;i++)qq.push(node(i,1,a[i]+b[1]));int c[800]; int ok=0;while(!qq.empty()){node t=qq.top();c[++ok]=t.s;qq.pop();if (ok==k){for (i=1;i<=k;i++)b[i]=c[i];return ;} if (t.b+1<=k)qq.push(node(t.a,t.b+1,a[t.a]+b[t.b+1])); }}int main(){int i,j;while(scanf("%d",&k)!=EOF){for (i=1;i<=k;i++){for (j=1;j<=k;j++){scanf("%d",&tm[i][j]);}sort(tm[i]+1,tm[i]+1+k);}for (j=1;j<k;j++){merge(tm[j],tm[j+1]); /*for (i =1;i<=k;i++)printf("%d ",tm[j+1][i]);cout<<endl;*/}for (i=1;i<=k;i++){if (i!=1) printf(" ");printf("%d",tm[k][i]);}printf("\n");}return 0;}


0 0