poj 2442 Sequence

本文介绍了一个寻找给定多个序列组合后形成的序列中,具有最小和的前n个序列的问题。通过对首个序列建立堆并结合后续序列进行排序和比较,逐步构建最小和序列。算法详细描述了如何维护一个堆以确保每次都能找到当前条件下的最小和。

 

Sequence

Time Limit: 6000MS Memory Limit: 65536K
Total Submissions: 9222 Accepted: 3074

Description

Given m sequences, each contains n non-negative integer. Now we may select one number from each sequence to form a sequence with m integers. It's clear that we may get n ^ m this kind of sequences.

Then we can calculate the sum of numbers in each sequence, and get n ^ m values. What we need is the smallest n sums. Could you help us?

Input

The first line is an integer T, which shows the number of test cases, and then T test cases follow. The first line of each case contains two integers m, n (0 < m <= 100, 0 < n <= 2000). 

The following m lines indicate the m sequence respectively. No integer in the sequence is greater than 10000.

Output

For each test case, print a line with the smallest n sums in increasing order, which is separated by a space.

Sample Input

1
2 3
1 2 3
2 2 3

Sample Output

3 3 4

 

对读入的第一个序列建堆,接下来的每个序列按升序排列,序列中第一个数加上堆中每一个数后加入另一个堆,对该行的第2个到第n个数每个数,

和堆里面每个数相加,如果比优先队列最大的元素小,那么弹出最大元素,压入该元素,比最大元素大,则break,跳到该行的下一个数。

<strong>
</strong>
const
  maxn=2000;
type
  arr=array[0..maxn] of longint;
var
  a,b,c:arr;
  i,j,k,l,t,n,m:longint;

procedure qsort(var x:arr;l,r:longint);
var
  i,j,k:longint;
begin
  if l>=r then exit;
  i:=l;j:=r;
  k:=x[(l+r) div 2];
  repeat
    while x[i]<k do inc(i);
    while x[j]>k do dec(j);
    if i<=j then
      begin
        x[0]:=x[i];x[i]:=x[j];x[j]:=x[0];
        inc(i);
        dec(j);
      end;
  until i>j;
  qsort(x,i,r);qsort(x,l,j);
end;

procedure up(i:longint);
var
  j:longint;
begin
  if i=1 then exit;
  j:=i div 2;
  repeat

    if c[i]>c[j] then
      begin
        c[0]:=c[i];
        c[i]:=c[j];
        c[j]:=c[0];
      end
    else break;
    i:=j;
    j:=j div 2;
  until i=0;
end;

procedure down(i:longint);
var
  done:boolean;
begin
  done:=false;
  repeat
    i:=2*i;
    if (i+1<=m) and (c[i]<c[i+1]) then inc(i);
    if c[i div 2]<c[i] then
      begin
        c[0]:=c[i];
        c[i]:=c[i div 2];
        c[i div 2]:=c[0];
      end
    else done:=true;
  until (2*i>m) or done;
end;

procedure inst(x,i:longint);
begin
  c[i]:=x;
  up(i);
end;

procedure instx(x,i:longint);
begin
  c[i]:=x;
  down(i);
end;

begin
  readln(t);
  for l:=1 to t do
    begin
      readln(n,m);
      for i:=1 to m do
        read(a[i]);
      readln;
      qsort(a,1,m);
      for i:=1 to n-1 do
        begin
          for j:=1 to m do
            read(b[j]);
          readln;
          qsort(b,1,m);
          for j:=1 to m do
            inst(a[j]+b[1],j);
          for j:=2 to m do
            for k:=1 to m do
              if b[j]+a[k]<c[1] then
                instx(b[j]+a[k],1)
              else break;
          a:=c;
          qsort(a,1,m);
          fillchar(c,sizeof(c),0);
        end;
      for i:=1 to m do
        write(a[i],' ');
      writeln;
    end;
end.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值