hdu 5884 Sort(二分+哈夫曼樹(隊列))

Sort

Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 1812    Accepted Submission(s): 455


Problem Description
Recently, Bob has just learnt a naive sorting algorithm: merge sort. Now, Bob receives a task from Alice.
Alice will give Bob N sorted sequences, and the i-th sequence includes ai elements. Bob need to merge all of these sequences. He can write a program, which can merge no more than k sequences in one time. The cost of a merging operation is the sum of the length of these sequences. Unfortunately, Alice allows this program to use no more than T cost. So Bob wants to know the smallest k to make the program complete in time.
 

Input
The first line of input contains an integer t0, the number of test cases. t0 test cases follow.
For each test case, the first line consists two integers N (2N100000) and T (Ni=1ai<T<231).
In the next line there are N integers a1,a2,a3,...,aN(i,0ai1000).
 

Output
For each test cases, output the smallest k.
 

Sample Input
1 5 25 1 2 3 4 5
 

Sample Output
3
 

Source
 
題意:有n個數,兩個數組合並的代價是兩個數組個數之和,總代價不能超過T,求每次最少可以合併的個數是多少?
思路:很明顯的二分然後判斷,問題是如何判斷?首先可以發現這裏有個貪心的思想,就是每次都合併最小的k個數,最後的結果會是最優的。
其次可能不能每次都找到k個,爲了維護二分的單調性,那麼我們可以補0,不會影響最後的結果。(想象一下哈夫曼樹多加一個權值爲0的葉子節點)

如果直接用優先隊列的話會TLE,我們這裏還需要一個模擬優先隊列的寫法。用兩個隊列,一個存初始數組,一個 存中間結果,每次要取k個只要取兩個之中小的一個,然後一個個取過去就好。  這裏省去一個排序的時間,因爲這兩個隊列一定是有序的,第一個自不必說,第二個因爲後面合併的k個數一定比前面要大,故一定也是有序的。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
using namespace std;
#define N 100005
long long a[N];
int check(int k,long long t,int n)
{
    queue<long long>first;///存初始數組
    queue<long long>second;///存中間結果的數組,注意都是有序的,不需要特意排序
    long long sum=0;
    if((n-1)%(k-1))///k叉哈夫曼樹要注意每次都要能找到k個數,不夠補0
    {
        for(int i=1; i<=k-1-(n-1)%(k-1); i++)
            first.push(0);
    }
    for(int i=1; i<=n; i++)
        first.push(a[i]);
    while(!first.empty()||!second.empty())
    {
        long long ans=0;
        for(int i=1; i<=k; i++)
        {
            if(!first.empty()&&!second.empty())
            {
                if(first.front()<=second.front())
                {
                    ans+=first.front();
                    first.pop();
                }
                else
                {
                    ans+=second.front();
                    second.pop();
                }
            }
            else if(first.empty()&&!second.empty())
            {
                ans+=second.front();
                second.pop();
            }
            else if(!first.empty()&&second.empty())
            {
                ans+=first.front();
                first.pop();
            }
            else break;
        }
        sum+=ans;
        if(sum>t) return 0;
        if(first.empty()&&second.empty()) break;
        second.push(ans);
    }
    return 1;
}
int main()
{
    int T;
    int n;
    long long t;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d %lld",&n,&t);
        for(int i=1; i<=n; i++)
            scanf("%lld",&a[i]);
        sort(a+1,a+1+n);
        int l=2,r=n,ans=n;
        while(l<r)///二分k
        {
            int mid=(l+r)>>1;
            if(check(mid,t,n)) ans=mid,r=mid;
            else l=mid+1;
        }
        printf("%d\n",l);
    }
    return 0;
}





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