标签:
题目描述:
恶魔把公主关到了地牢(m x n 的grid)的右下角,骑士要从左上角的位置出发到达公主所在的位置解救公主
每个位置都有一个hp值,当骑士到达一个位置时,骑士的hp要加上该位置的hp(当该位置的hp小于0时,hp减少;当该位置的hp大于0时,hp增加)
骑士每次只能往下或者往右走
当骑士的hp值为0是,骑士立即die
计算骑士开始最少要有到少hp,才能到达右下角解救公主(开始位置和公主位置相应的hp也要计算)
题目分析:
求最优解,首先考虑dp
设置状态: d[i][j],表示从(i,j)位置到右下角开始需要最少的hp值
状态转移: d[i][j]=min(d[i+1][j],d[i][j+1])-dungeon[i][j]
从又下角到左上角递推
边界: 对最后一列和最后一行特殊处理
注意:d[i][j] <= 0是无意义的,当d[i][j]<=0时实际上表示的是在该位置,不需要额外的hp值,就可以到达右下角
但是要注意任何时候hp值不能小于等于0,这个时候d[i][j]应该设置为1,来表示不需要额外的hp值
所以对上面状态转移添加一点, 每次计算的d[i][j]之后,d[i][j]的实际值应该是 d[i][j] = d[i][j] > 0 ? d[i][j] : 1
结果:d[0][0]
优化
注意到上面状态转移方程,当前状态只用到了相邻一行的数据,这样可以利用滚动数组压缩空间为 O(n)
代码:
递推
1 int live(int next,int dun){
2 int ret=next-dun;
3 if(ret<=0)ret=1;
4 return ret;
5 }
6
7 int calculateMinimumHP(vector<vector<int> > &dungeon) {
8 int lenx=dungeon.size();
9 if(lenx<=0)return 0;
10 int leny=dungeon[0].size();
11 if(leny<=0)return 0;
12
13 vector<int>d[2];
14
15 int tag=0;
16 for(int j=0;j<leny;j++)d[0].push_back(0),d[1].push_back(0);
17
18 d[tag][leny-1]=live(1,dungeon[lenx-1][leny-1]);
19 for(int j=leny-2;j>=0;j--)
20 d[tag][j]=live(d[tag][j+1],dungeon[lenx-1][j]);
21
22 for(int i=lenx-2;i>=0;i--){
23 tag=1-tag;
24 d[tag][leny-1]=live(d[1-tag][leny-1],dungeon[i][leny-1]);
25
26 for(int j=leny-2;j>=0;j--){
27 d[tag][j]=live(min(d[1-tag][j],d[tag][j+1]),dungeon[i][j]);
28 }
29 }
30
31 return d[tag][0];
32 }
标签:
原文地址:http://www.cnblogs.com/li-xingtao/p/4212029.html