有序表的最小和

有序表的最小和

【問題描述】

給出長度爲n得有序表A和B,在A和B中各取一個元素,可以得到n^2個和,求這些和中最小的n個

【輸入格式】

第一行包含一個整數n(n<=400000)

第二行與第三行分別n個整數,從小到大排列

【輸入樣例】

3

1 2 5

2 4 7

【輸出樣例】

3

4

5

【算法分析】

由題意知,

A[1]<=A[2]<=A[3]<=a[4]...

B[1]<=B[2]<=B[3]<=B[3]...

設C[a,b]=A[a]+B[b]

可知對於每一個a來說

C[a,1]<=C[a,2]<=C[a,3]...

此時C[a]構成一個數列

每一次生成的最小值必定是C[a](1<=a<=n)每個數列的頭中最小的

例如

1 2 5

2 4 7

C[a,b]

a/b 1 2 3

1 3 5

2 4 6 9

3 7 9 12

第一個最小的數必定在3,4,7三數之間 爲3,3去掉,此時c[1]表頭爲5

第二個最小的數必定在5,4,7三數之間 爲4,   4去掉,此時c[2表頭爲6

第三個最小的數必定在5,6,9三數之間 爲5, 5去掉,此時c[1]表頭爲8

【算法實現】

由此我們可以維護一個小根堆

開始時這個堆有n個元素,它們爲每個表的頭元素c[a,1](1<=a<=n)

每次取出小根堆的根元素並將該元素所在表的表頭更新:其實並沒有必要建表,只需修改該根元素的值爲該表下一個值即可

維護堆,重複n次

【程序】

<span style="font-size:14px;">//2016-4-7
//Gods save princess!
//By Shui'bing ICEE
const
  maxn=500000;//!!!!!
type
  node=record
    b,data:longint;
  end;
var
  heap:array[0..maxn] of node;
  a,b:array[0..maxn] of longint;
  i,n,l:longint;
  procedure put(x,b:longint);
var
  son,temp:longint;
begin
  inc(l);
  heap[l].b:=b;
  heap[l].data:=x;
  son:=l;
  while (son<>1) and (heap[son div 2].data>heap[son].data) do
    begin
      temp:=heap[son div 2].data;
      heap[son div 2].data:=heap[son].data;
      heap[son].data:=temp;
      temp:=heap[son div 2].b;
      heap[son div 2].b:=heap[son].b;
      heap[son].b:=temp;
    end;
end;
  function get:longint;
var
  fa,son,temp:longint;
  stop:boolean;
begin
  get:=heap[1].data;
  heap[1].data:=heap[1].data-b[heap[1].b]+b[heap[1].b+1];
  inc(heap[1].b);
  fa:=1;
  stop:=false;
  while (fa*2<=l) and (not stop) do
    begin
      if (fa*2+1>l) or (heap[fa*2].data<heap[fa*2+1].data)
      then son:=fa*2
      else son:=fa*2+1;
      if heap[fa].data>heap[son].data
      then begin
             temp:=heap[fa].data;
             heap[fa].data:=heap[son].data;
             heap[son].data:=temp;
             temp:=heap[fa].b;
             heap[fa].b:=heap[son].b;
             heap[son].b:=temp;
           end
      else stop:=true;
    end;
end;
begin
  read(n);
  for i:=1 to n do
    read(a[i]);
  for i:=1 to n do
    read(b[i]);
  l:=0;
  for i:=1 to n do
    begin
      put(a[i]+b[1],1);
    end;
  for i:=1 to n do
      writeln(get);
end.</span>


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章