我一直在尝试解决the following TopCoder problem:
你正在玩一个策略游戏,你希望训练最强大的军队进行最后的战斗。游戏中有N级生物,编号从0到N-1(包括0和N-1)。你已经在你的军队中有一些生物和D天来训练他们。你拥有的生物数量以int []计数给出。它包含N个元素,其第i个元素是级别i的生物数量。
在每一天,你可以选择一个生物并进行训练。训练将生物的等级提高1,即等级0的生物变为等级1的生物,等级1的生物变为等级2的生物,依此类推。唯一的例外是N-1级别的生物 - 这样的生物无法训练,因为N-1是最大可能的等级。您可以在一天以上的时间内训练同一个生物。例如,如果你在3天内训练一个生物,它将获得3个等级。在那些日子里,你也可以跳过几天而不训练任何生物。
你被赋予一个int []的力量,其中第i个力量元素是一个等级为i的生物的力量。你的军队的力量是其所有生物的力量的总和。在所有D天的训练结束后,返回你的军队可以拥有的最大可能力量。
我无法获得算法。这是一个动态编程问题,我无法找到任何合适的子问题来解决它。
任何人都可以向我提供解决问题需要考虑的子问题吗?
我也想知道你到达解决方案的思维过程。
答案 0 :(得分:1)
Topcoder包括为他们的问题提供解决方案的社论。
解决方法是here:
我们可以完全自由地进行升级。在寻找时 最优算法,自由是坏的 - 它给了我们太多 尝试的可能性。我们如何限制搜索?
我们可以决定在进行升级时有点系统化。我们会 首先花一些(可能是零)天升级0级 生物,然后我们将升级一些1级生物,依此类推。 显然,通过这种方式,我们将能够实现最佳的总功率。 (如果我们有一个最佳解决方案,可以在其他方面进行升级 顺序,我们可以轻松地重新排列它们并按照我们的顺序进行。)
现在我们可以轻松编写一个可以尝试所有的递归解决方案 可能性。当然,我们想要记住计算值 避免指数时间复杂性。为此,我们需要确定 正是用于描述计算状态的内容。
两个参数是显而易见的:我们生物的等级L. 目前正在升级,剩下的D天数。但是,这是 不是全部,还有一个更重要的问题。我们可能已经做了一些 之前的升级,以及当前L级生物的数量 可能高于输入值。这个差异将是第三个, 最后,参数。
最多N = 50级,最多D = 100天。显然, 第三个参数永远不能超过D.因此最多 N * D * D = 500,000个州。计算一个状态的时间复杂度是 O(D),导致总时间复杂度O(N * D ^ 3)。
long long memo[52][102][102];
long long counts[52], powers[52];
int N;
long long solve(int level, int add, long long upgrades) {
long long &res = memo[level][add][upgrades];
if (res >= 0) return res;
res = 0;
if (level==N) return res;
int maxUpgrades = min( upgrades, counts[level]+add );
for (int now=0; now<=maxUpgrades; now++) {
long long thisLevel = powers[level] * (counts[level]+add-now);
long long nextLevels = solve(level+1,now,upgrades-now);
res = max( res, thisLevel+nextLevels );
}
return res;
}
long long maximumPower(vector <int> _count, vector <int> _power, int D) {
memset(memo,-1,sizeof(memo));
N = _count.size();
for (int i=0; i<N; i++) counts[i] = _count[i];
for (int i=0; i<N; i++) powers[i] = _power[i];
return solve(0,0,D);
}
答案 1 :(得分:0)
它看起来像一个dp,很有意思我想尝试一下..我会以这种方式接近它:
我创建了一个级别之间的权力差异数组,然后追求升级低于该级别的生物,以获得我可以添加的最大功率。我认为这可能是一个贪婪或背包,升级的是关键决定。
编辑:好吧,我忘了提到你应该对这个数组做什么:你应该对它进行排序以获得排序的索引..它实际上比数组更像是一个数据,因为你想要在进程中混洗索引排序,以便你可以知道哪个级别是最高的差异,正面或负面等等。