找到能给出最小能量的路径

时间:2012-12-08 11:59:30

标签: algorithm dynamic data-structures recursion graph

ACM国际大学生程序设计竞赛,Asia-Amritapuri网站,2011年 问题A:MAGRID

非常感谢帮助哈利波特在10月份找到巫师的不朽之石。我们没有告诉你它只是一个在线游戏吗?唔!现在这里是哈利真正的现场任务。您将获得一个具有R行和C列的magrid S(魔术网格)。这个大杂烩的每个细胞都有一个我们勇敢的英雄必须击败的匈牙利恐龙,或者是他的老师斯内普为他留下的一瓶魔法药水。单元格中的龙(i,j)带走| S [i] [j] |他的力量点,一个细胞(i,j)的魔药增加了哈利的力量S [i] [j]。如果他的旅程中任何时候他的力量降到0或更低,那么哈利就会死去,没有任何神奇的石头可以让他复活。

Harry从左上角的单元格(1,1)开始,而Sorcerer的Stone则在右下角的单元格(R,C)中。从一个单元格(i,j),哈利只能向下或向右移动一个单元格,即向单元格(i + 1,j)或单元格(i,j + 1)移动,并且他不能移动到该单元格之外。哈利在开始他的旅程之前已经使用了魔法来确定哪个细胞包含什么,但缺乏基本的简单数学技能来确定他需要从收集魔法师之石开始时需要的最小力量。请再次帮助他。

  

输入(STDIN):

     

第一行包含测试案例的数量T.T案例如下。   每个测试用例包括第一行中的R C,然后是   R行中的网格描述,每行包含C个整数。行   从上到下编号为1到R,列编号为1到C.   从左到右。具有S [i] [j] <1的细胞。 0包含龙,其他   含有魔药。

     

输出(STDOUT):

     

输出T线,每种情况一个包含最小强度   哈利应该从细胞(1,1)开始积极   通过他的电池之旅(R,C)的力量。

约束:

1 ≤ T ≤ 30
2 ≤ R, C ≤ 500
-103 ≤ S[i][j] ≤ 103
S[1][1] = S[R][C] = 0

时间限制:3秒 内存限制:64 MB 样本输入:

3
2 3
0 1 -3
1 -2 0
2 2
0 1
2 0
3 4
0 -2 -3 1
-1 4 0 -2
1 -2 -3 0

示例输出:

2
1
2

说明: 案例1:如果Harry在单元格(1,1)处以强度= 1开始,则他无法在任何可能的路径中保持正向力量。他最初需要至少力量= 2。 案例2:请注意,从(1,1)开始,他至少需要strength = 1.

我尝试用我的第一种方法来查看所有路径并选择能量最小的路径

#include<iostream>
#include<algorithm>
#include<stack>
#include<cmath>
using namespace std;

int TT,R,C,S[500][500];
int energy_g;
//unsigned long int fact(int a);
int trace(int r,int c,int energy,int energy_r);
int main(void)
{

    cin>>TT;

    for(int i=1;i<=TT;i++)
    {
    cin>>R>>C;     
    for(int r=1;r<=R;r++)
         for(int c=1;c<=C;c++)
         {
             cin>>S[r][c];
         //cout<<S[r][c];   
         }
     energy_g=32000;
     trace(1,1,0,0);
     cout<<energy_g<<endl;
    }
    return 0;
}

int trace(int r,int c,int energy,int energy_r)
{
    if(r>R || c>C)
        return 0;
    energy += S[r][c];
    if(energy < 0)
    {
    energy_r+=abs(energy)+1 ;       
    energy+=abs(energy)+1;
    }


    else if(energy == 0){        
    energy_r +=1;   
    energy +=1;
     }

    if(r == R && c == C)
    {

    if(energy_r < energy_g)
            energy_g = energy_r;
        return 0;
    }
    trace(r,c+1,energy,energy_r);
    trace(r+1,c,energy,energy_r);
    return 0;
}

请帮助我进一步优化它,因为我知道我实施的方法花费的时间最短

1 个答案:

答案 0 :(得分:2)

这是我头脑中的解决方案。我们将使用相当常见的技巧 - 二进制搜索答案。解决方案可分为两部分:

1)检查我们是否可以用N的健康水平完成旅程。这可以通过简单的动态编程来完成 - 让dp[i][j]成为我们进入细胞时可以拥有的最大能量水平(i ,J)。由于我们只能向下或向右移动,dp[i][j]可以归结为(i-1,j)和(i,j-1)中最好的移动。如果等级低于1,则将值设置为负无穷大,因为我们无法承受Harry死亡:)(或者在执行DP步骤时添加检查以排除不可能的切片)。 dp[0][0]为N,dp[i][0]dp[0][i]可以立即计算。然后继续进行表格填充。要想象,请查看http://www.cs.berkeley.edu/~vazirani/algorithms/chap6.pdf的图6.4。

2)对答案进行二元搜索。最初是left = 1right = 2000000000(或其他合适的上限) - 这些是二进制搜索的左右边界。在二次搜索的每次迭代中,我们检查我们是否可以使用mid = (left+right)/2的健康级别完成旅程并递归到适当的一半。

这在实践中效果很好 - 每个DP步骤需要O(R * C)时间,二进制搜索会增加一个log(2000000000)因子,大约为30.这应该没问题。

它可能只能用DP解决,但我现在看不清楚。