解决SPOJ DIEHARD的正确方法是什么?

时间:2012-10-19 14:07:04

标签: c++ algorithm recursion dynamic-programming greedy

我试图在SPOJ https://www.spoj.pl/problems/DIEHARD/上解决练习题。 然而,我的贪婪方法导致错误的答案和递归对于最坏的情况来说太慢。任何人都可以告诉如何解决这个问题?我正在寻找有人指出我正确的方向。

  

游戏很简单。你最初有'H'的健康和'A'量的护甲。在任何时刻,您都可以居住在三个地方中的任何一个地方 - 火,水和空气。每个单位时间之后,你必须改变你的生活地点。例如,如果你现在生活在火中,你可以进入水中或空气中。

     
      
  • 如果你进入空中,你的生命值会提高3点,你的护甲会增加2点
  •   
  • 如果你踏入水中,你的生命值会降低5点,你的护甲会降低10点   如果你步入火中,你的生命值会降低20点,你的护甲会增加5点
  •   
     

如果您的健康或护甲变为<= 0,您将立即死亡

     

找出你能活下来的最长时间。

     

输入:

     

第一行包含整数t,即测试用例的数量。对于每个测试用例,将有两个正整数代表初始健康H和初始护甲A.

     

输出:

     

对于每个测试用例,找到您可以存活的最长时间。

3 个答案:

答案 0 :(得分:1)

以下是另一种分析方法:

a = number of times visiting air state
F = number of times visiting fire state
W = number of times visiting water state

M = a + F + W  // total moves

// positive
a >= 0
F >= 0
W >= 0

// because of the restriction of moving between states...
a <= F + W + 1
F <= W + a + 1
W <= a + F + 1

// the effect of armor and health...
H < -3a + 5H + 20F
A < -2a + 10W - 5F

最大化M.您可以通过二进制搜索M来完成此操作,或者您可以使用线性编程。

二进制搜索循环:

int ok = 0;
int impossible = 1000000000;
while (impossible - ok > 1)
{
    int candidate = ok + (impossible-ok) / 2;

    if (check(candidate))
        ok = candidate;
    else
        impossible = candidate;
}
return ok;

在任何一种情况下都使用基本的高中代数来简化不等式/方程式。

答案 1 :(得分:0)

你试过DFS吗?状态是(空气,水,H,A)的元组。这有:

3 * 1000 * 1000 = 3,000,000 game states

对其进行DFS并找到最高动作。 (即将所有内容设置为-1,将初始状态设置为0,然后将DFS从0状态设置为所有可到达位置)

答案 2 :(得分:0)

我通过使用动态编程来完成。 Dp [健康] [护甲] [空气/火/水] - 如果你从这个状态开始你可以活的最长时间 那么经常性的条件就变成了 Dp [健康] [护甲] [空气/火/水] =你可以去的下一个状态的1 +最大值 很明显,基本情况是他无处可去,所以答案就是零。