我在Google Code Jam中阅读了optimisation problem about energy。 (比赛结束了,所以可以谈论它)
今天你的日历非常繁忙,有很多重要的事情要做。 你努力准备并确保所有的活动都没有 交叠。现在是早上,你担心尽管如此 热情,你将无法全力以赴地完成这一切 接合。
你必须仔细管理你的能量。你开始一整天 能量 - 准确地说是能量的E焦耳。你知道你不能去 低于零焦耳,或者你将从疲惫中堕落。你可以花任何钱 每项活动的非负,整数焦耳(您可以花费 零,如果你觉得懒惰),并在每次活动后你将重新获得R. 焦耳的能量。然而,无论你多么懒惰,你都不能拥有 任何时候都超过E焦耳的能量;你会有多余的能量 重拾过去这一点是浪费。
现在,有些事情(比如解决Code Jam问题)更为重要 相对于其它的。对于第i个活动,您有一个表达的值vi 这项活动对你有多重要。你从每个人获得的收益 活动是活动的价值,乘以金额 你花在活动上的能量(焦耳)。你想管理你的 能量使你的总收益尽可能大。
请注意,您无法对日历中的活动重新排序。你刚才 必须用你的日历来管理你的能量 有
输入
输入的第一行给出了测试用例的数量,T.T test 案件如下。每个测试用例由两行描述。首先 包含三个整数:E,最大(和初始)量 能量,R,每次活动后你恢复的数量,和N, 当天计划的活动数量。第二行包含N. 整数vi,描述您计划的活动的价值 今天。
输出
对于每个测试用例,输出一行包含“Case #x:y”,其中x 是案例编号(从1开始),y是您可以获得的最大增益 通过当天管理你的能量来实现。
如何解决这个问题?我在想它是否可以通过动态编程来解决。任何线索?
答案 0 :(得分:1)
它可以简单地通过递归完成,下面附带代码:这里状态是v的数组,如问题
public static long calculate(long limit,long initialEnergy,long R,long[] status,int start){
long leftEnergy = 0;
long maxGain = 0;
if(start + 1 > status.length){
return 0;
}
for(long taskEnergy = initialEnergy; taskEnergy>=0;taskEnergy--){
leftEnergy = initialEnergy - taskEnergy + R;
if(leftEnergy > limit){
leftEnergy = limit;
}
long gain = status[start] * taskEnergy + calculate(limit,leftEnergy, R, status, start +1);
if(gain > maxGain){
maxGain = gain;
}
}
//System.out.println(start + " " + maxGain);
return maxGain;
}
答案 1 :(得分:-1)
想象一下在每个活动上花费的能量作为多维空间中的坐标。想象一下,作为多维空间中点的温度而获得的增益。 (将不可能的组合视为零增益。)这将问题减少为“找到房间中最热点”。这很容易 - 从任何地方开始(可能,为简单起见,从每个活动消耗的零能量开始,因为至少确保合法),继续向任何方向移动,使其更热,并在没有方向使其更热时停止。
直观地说,在我看来,你不能陷入局部最大值(因为输出是输入的线性,钳位函数)。但是如果你担心它,当你停下来时,“随意”踢自己“然后再试一次。如果你重复这几次并在同一地点持续着陆,你可以合理地确信这是全球最大值。
使用重力隐喻,基本上,您将问题映射到空间。您将最佳解决方案映射到空间中的最低点。然后它就像落到底部一样简单。