HDU 5884 Sort 2分 K叉哈夫曼树

题目

Sort

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


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

题目大意


  给你一组数(无序的),ai代表有ai个元素,要求我们把这些数合并成一个数,每次合并的数量是固定的,每次合并的花费你合并的数的和,例如你合并ai,aj,就就要花费SUM(ai+aj),但是你总的花费不能超过T,Bob想知道每次合并的数量最少是几?

 

解题思路


 刚开始直接从1开始找,发现傻了点,这样的题,最适合二分,每次二分K,然后比较一下K叉哈夫曼树和T就可以啦,哈夫曼树不会的建议好好学习一下数据结构。


#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
#define LL long long
const int maxn =100000+10;
LL a[maxn];//存数的数组
LL b[maxn];//存加和的数组
int N;
int Hafuman(int k)  //返回总代价,O(2*n)
{
	int ai, bi, blen;
	blen = 0;
	ai = bi = 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;
	}
	return cost;
}
int main()
{
    int t;
    LL T;
    scanf("%d",&t);
    while(t--)
    {
      scanf("%d%lld",&N,&T);
      for(int i=0;i<N;i++)
        scanf("%lld",a+i);

      sort(a,a+N);

      int l=2,r=N;
      while(l<r)
      {
          int mid=(l+r)>>1;
          if(Hafuman(mid)<=T)
          {
              r=mid;
          }
          else
          {
              l=mid+1;
          }
      }
      printf("%d\n",r);
    }
    return 0;
}





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值