1.题面
http://acm.fzu.edu.cn/problem.php?pid=2219
2.题意
你有m个工人,要造n个建筑,每个工人只能建造一个建筑,每个建筑只能被一个工人造。但是你有一项技能,你可以选择一个工人,把他变成一个蛋,这样k个时间单位后,这个蛋就会孵化出两个工人。
现在给出建造第i栋建筑需要的时间t[i],求建造完这所有n栋建筑需要的时间。
3.思路
这道题中每一种建造方案都可以用图来表示,图中有m棵二叉树,表示m个初始工人,每一次分叉都是使用魔法将一个工人变成两个工人,因为每次需要k单位的时间,所以我们将每条边的权值设置为k,分叉节点的权值设为0。然后如果这个工人不再进行分裂,而是去做建造第i个建筑,它的下方就直接接一个权值为t[i]的节点。
为了说明的方便,我们引入一个虚的根节点,从根节点往这m棵树的树根每个都引一条权值为0的边。
那么我们的问题就变成了,找出一种方案,使所有叶子节点到虚的根节点中的权值和的最大值最小。
在这样一棵树中,所有的叶子节点都代表一个建设建筑物的操作。
可以证明,如果一个(距离根节点较远的叶子节点)的权值大于(一个距离根节点距离较小的节点),我们交换这两个节点之后结果必然不会更坏,而且有可能会更好。
根据以上性质,我们可以推测出,在一棵最优的树中权值最小的两个节点,距离根节点的距离也必然是最大的。至于为什么是两个呢,因为权值最小的节点必然有兄弟啊。
这个样子,我们就找到了最底端的两个节点,同时也解决了这个问题。因为在找到了最底端的两个节点之后,我们可以将它们删除,同时将它们的父亲节点的权值设置为max(LeftChild,RightChild)+k。我们的问题就变成了如何是剩下的节点最优,这是一个已经解决的问题。
ZB loves playing StarCraft and he likes Zerg most!
One day, when ZB was playing SC2, he came up with an idea:
He wants to change the queen's ability, the queen's new ability is to choose a worker at any time, and turn it into an egg, after K units of time, two workers will born from that egg. The ability is not consumed, which means you can use it any time without cooling down.
Now ZB wants to build N buildings, he has M workers initially, the i-th building costs t[i] units of time, and a worker will die after he builds a building. Now ZB wants to know the minimum time to build all N buildings.
The first line contains an integer T, meaning the number of the cases. 1 <= T <= 50.
For each test case, the first line consists of three integers N, M and K. (1 <= N, M <= 100000, 1 <= K <= 100000).
The second line contains N integers t[1] ... t[N](1 <= t[i] <= 100000).
For each test case, output the answer of the question.
2 3 1 1 1 3 5 5 2 2 1 1 1 1 10
6 10
For the first example, turn the first worker into an egg at time 0, at time 1 there’s two worker. And use one of them to build the third building, turn the other one into an egg, at time 2, you have 2 workers and a worker building the third building. Use two workers build the first and the second building, they are built at time 3, 5, 6 respectively.
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<vector>
#include<queue>
using namespace std;
int main()
{
ios::sync_with_stdio(false);
int n,m,k,i,j,T,t;
cin>>T;
while(T--) {
priority_queue<int,vector<int>,greater<int> > que;
cin>>n>>m>>k;
for(i=1;i<=n;i++) {
cin>>t;
que.push(t);
}
while(que.size()>m) {
que.pop();
t = que.top();
que.push(t+k);
que.pop();
}
while(que.size()>1) que.pop();
cout<<que.top()<<endl;
}
return 0;
}