Algorithm 寻找能量最小的路径

Algorithm 寻找能量最小的路径,algorithm,dynamic,data-structures,recursion,graph,Algorithm,Dynamic,Data Structures,Recursion,Graph,ACM国际大学生编程大赛,亚洲阿姆利塔普里网站,2011年 问题A:马格里德 非常感谢你在十月份帮助哈利波特找到了不朽的魔法石。我们没有告诉你这只是一个在线游戏吗?啊!!现在这是哈利真正的现场任务。您将得到一个具有R行和C列的magrid S(魔法网格)。这只马格里德的每个牢房里要么有一条我们无畏的英雄必须打败的匈牙利角尾龙,要么有一瓶他的老师斯内普留给他的魔药。牢房里的龙(i,j)会从哈利身上拿走| S[i][j]|力量点,牢房里的魔药(i,j)会增加哈利的力量S[i][j]。如果他的力量在旅

ACM国际大学生编程大赛,亚洲阿姆利塔普里网站,2011年 问题A:马格里德

非常感谢你在十月份帮助哈利波特找到了不朽的魔法石。我们没有告诉你这只是一个在线游戏吗?啊!!现在这是哈利真正的现场任务。您将得到一个具有R行和C列的magrid S(魔法网格)。这只马格里德的每个牢房里要么有一条我们无畏的英雄必须打败的匈牙利角尾龙,要么有一瓶他的老师斯内普留给他的魔药。牢房里的龙(i,j)会从哈利身上拿走| S[i][j]|力量点,牢房里的魔药(i,j)会增加哈利的力量S[i][j]。如果他的力量在旅途中的任何时候下降到0或更少,哈利就会死亡,没有魔法石能使他复活

哈利从左上角的牢房(1,1)开始,魔法石在右下角的牢房(R,C)。从一个单元格(i,j),哈利只能向下或向右移动一个单元格,即移动到单元格(i+1,j)或单元格(i,j+1),他不能移动到magrid之外。哈利在开始他的旅程之前使用了魔法来确定哪个细胞含有什么,但缺乏基本的简单数学技能来确定他需要从哪种最小强度开始收集魔法石。请再次帮助他

输入(标准输入):

第一行包含测试用例的数量。 每个测试用例由第一行中的rc和后面的 用R行描述网格,每行包含C个整数。排 从上到下编号为1到R,列编号为1到C 从左到右。S[i][j]<0的单元格包含龙,其他 包含魔法药剂

输出(标准输出):

输出T线,每箱一条,包含最小强度 Harry应该从细胞(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)开始,他至少需要力量=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;
}
#包括
#包括
#包括
#包括
使用名称空间std;
int TT,R,C,S[500][500];;
国际能源集团;
//无符号长整数事实(整数a);
int跟踪(int r,int c,int energy,int energy_r);
内部主(空)
{
cin>>TT;
对于(inti=1;i>R>>C;
对于(int r=1;rS[r][c];

//cout这是我脑海中的一个解决方案。我们将使用非常常见的技巧-对答案进行二进制搜索。解决方案可分为两部分:

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]
可以立即进行计算。然后进行类似表格的填充。要可视化,请参阅的图6.4

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

这将在实践中很好地工作-每个DP步骤都需要O(R*C)时间,二进制搜索会添加一个log(2000000000)因子,大约30。这应该可以


这个问题可能只用DP就可以解决,但我现在不知道怎么解决。

提示:反向计算,每次计算从某个位置(I,j)获得的能量时最后,记住它,这样你就不必再次计算:)不需要进行二进制搜索。详细说明@j_random_hacker的提示:你可以从右到左直接计算底部行的每个单元格所需的最小能量。最右边的列也一样,从下到上。其他单元格可以计算一次计算它们的右下邻域和右下邻域,这显然比二进制搜索效率低一些