Sort HDU - 5884(k叉赫夫曼树)

传送门

K叉哈夫曼树

题意:让你合并n个有序序列,合并k个有序序列的花费为k个序列的长度之和,问合并n个序列在不大于T的花费情况下。每次选择k个序列进行合并的k最小为多少。 
题解:k叉哈夫曼树。找了一个k叉哈夫曼树的模板返回的是构造这个树的代价。然后二分找k的值。如果代价ans大于T,说明这个二分的k值小了,反之大了。

附上代码:


#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>

using namespace std;

typedef long long ll;

const int maxn=1e5+50;

ll a[maxn],b[maxn];
ll n,m;

ll huffman(int k)
{
    ll ai,bi,blen;
    ai=bi=0;
    blen=0;
    ll cost=0;
    bool first=true;
    while(n-ai+blen-bi>1){
        int num=0;
        if(first){
            if((n-k)%(k-1)==0){
                num=k;
            }else{
                num=(n-k)%(k-1)+1;
            }
            first=false;
        }else{
            num=k;
        }
        ll sum=0;
        while(num--){
            if(ai==n){
                sum+=b[bi];
                bi++;
            }else if(bi==blen){
                sum+=a[ai];
                ai++;
            }else if(a[ai]<b[bi]){
                sum+=a[ai];
                ai++;
            }else{
                sum+=b[bi];
                bi++;
            }
        }
        cost+=sum;
        b[blen++]=sum;
        if(cost>m){
            return m+1;
        }
    }
    return cost;
}

int main()
{
    int t;
    scanf("%d",&t);
    while(t--){
        scanf("%lld%lld",&n,&m);
        for(int i=0;i<n;i++){
            scanf("%lld",&a[i]);
        }
        sort(a,a+n);
        int l=0,r=n;
        while(l<r){
            int mid=(l+r)>>1;
            ll tmp=huffman(mid);
            if(tmp<=m){
                r=mid;
            }else{
                l=mid+1;
            }
        }
        printf("%d\n",r);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/zhouzi2018/article/details/81265660