Judge:http://acm.hdu.edu.cn/showproblem.php?pid=5884
题意:给出N个节点,构造一颗k叉哈夫曼树,使每个结点的权值乘以距离的和小于等于给出的和。求k的最小值。(N<=100000)
二分 + k叉哈夫曼树
k叉哈夫曼树有两种构造方法,利用优先队列的方法会超时,这里采用另一种方法。
#include <cstdio>
#include <algorithm>
#include <queue>
#include <cstring>
using namespace std;
struct SNode {
long long iData, iSum;
};
bool operator > (const SNode a, const SNode b)
{
return a.iData > b.iData;
}
bool operator < (const SNode a, const SNode b)
{
return a.iData < b.iData;
}
long long iTimeTot;
int arrSeq[100010], iSeqTot;
bool Solve(int iLimit)
{
queue<SNode> queA, queB;
SNode nodeTmp, nodeSum;
nodeTmp.iData = nodeTmp.iSum = 0;
if ((iSeqTot - 1) % (iLimit - 1))
for (int i = 1; i <= (iLimit - 1) - (iSeqTot - 1) % (iLimit - 1); i++)
queA.push(nodeTmp);
for (int i = 1; i <= iSeqTot; i++)
{
nodeTmp.iData = arrSeq[i];
queA.push(nodeTmp);
}
while (!queA.empty() || queB.size() > 1)
{
nodeSum.iData = nodeSum.iSum = 0;
for (int i = 1; i <= iLimit; i++)
{
if (queA.empty() && queB.empty())
break;
if (queB.empty() || (!queB.empty() && !queA.empty() && queA.front() < queB.front()))
{
nodeSum.iData += queA.front().iData;
nodeSum.iSum += queA.front().iData + queA.front().iSum;
queA.pop();
}
else
{
nodeSum.iData += queB.front().iData;
nodeSum.iSum += queB.front().iData + queB.front().iSum;
queB.pop();
}
}
queB.push(nodeSum);
}
return !queB.empty() && queB.front().iSum <= iTimeTot;
}
int main()
{
int iCaseTot;
scanf("%d", &iCaseTot);
while (iCaseTot--)
{
memset(arrSeq, 0, sizeof(arrSeq));
scanf("%lld %lld", &iSeqTot, &iTimeTot);
for (int i = 1; i <= iSeqTot; i++)
scanf("%d", &arrSeq[i]);
sort(arrSeq + 1, arrSeq + 1 + iSeqTot);
int iLeft = 1, iRight = iSeqTot, iMid;
while (iLeft + 1 < iRight)
{
iMid = iLeft + (iRight - iLeft) / 2;
if (Solve(iMid))
iRight = iMid;
else
iLeft = iMid;
}
printf("%d\n", iRight);
}
return 0;
}
这道题的输出居然丧心病狂地要求
必须有一个空行,注意是
必须有,而不是
可以有。