試題 算法訓練 步與血
資源限制
時間限制:1.0s 內存限制:256.0MB
問題描述
有n×n的方格,其中有m個障礙,第i個障礙會消耗你p[i]點血。初始你有C點血,你需要從(1,1)到(n,n),並保證血量大於0,求最小步數。
輸入格式
第一行3個整數n,m,c,表示棋盤大小、障礙數量和你的血量
接下來m行,每行描述一個障礙。包含三個整數x y p,分別表示障礙在第x行第y列,消耗血量爲p。
輸出格式
如果可以到輸出步數,如果不可以,輸出"No"。
樣例輸入
10 10 10
2 8 35
1 10 25
9 9 63
5 6 46
2 6 43
8 7 92
5 3 54
3 3 22
7 9 96
9 10 13
樣例輸出
18
數據規模與約定
輸入數據中每一個數的範圍。
0<n,m<100,
試題解析
步數最小就得每次只能向下或向右走,那麼這樣就很容易取動態規劃了設dp.co[i][j]爲走到(i,j)位置需要的步數那麼dp.co[i][j]=min(dp.co[i-1][j],dp.co[i][j-1])但其中有障礙所以還需要保存到每個位置的血量>0,否則說明這個點不能走
代碼
#include <stdio.h>
typedef struct s{
int co[101][101];// 走到(i,j)需要的最小步數
int blood[101][101];// 走到(i,j)剩餘的血量
}step;
int main() {// n、m、c、x、y、p對應題意
int n, m, c, x, y, p, i, j;
scanf("%d%d%d",&n,&m,&c);
int chess[101][101] = {0};// 棋盤chess的值爲此處消耗的血量
for(i = 0;i < m; ++i) {
scanf("%d%d%d",&x,&y,&p);
chess[x][y] = p;
}
step dp;
dp.blood[1][1] = c;// 初始化血量
dp.co[1][1] = 0;// 初始化步數
for(i = 2;i <= n; ++i) {// 初始化第一行第一列
dp.co[1][i] = dp.co[1][i-1]+1;// 從(1,i-1)到(1,i)步數+1
dp.blood[1][i] = dp.blood[1][i-1]-chess[1][i];// 去掉消耗的血量
if(dp.blood[1][i] <= 0) {// 血量不大於0說明這裏不能走步數設爲0
dp.co[1][i] = 0;
}
dp.co[i][1] = dp.co[i-1][1]+1;
dp.blood[i][1] = dp.blood[i-1][1]-chess[i][1];
if(dp.blood[i][1] <= 0) {
dp.co[i][1] = 0;
}
}
for(i = 2;i <= n; ++i) {// 從(2,2)開始遞推
for(j = 2;j <= n; ++j) {
if(dp.co[i-1][j]>0 && dp.co[i][j-1]>0) {// 左邊和上邊步數不爲0說明都能通行
if(dp.co[i-1][j] <= dp.co[i][j-1]) {
dp.co[i][j] = dp.co[i-1][j]+1;
dp.blood[i][j] = dp.blood[i-1][j]-chess[i][j];
if(dp.blood[i][j] <= 0) {
dp.co[i][j] = 0;
}
}else {
dp.co[i][j] = dp.co[i][j-1]+1;
dp.blood[i][j] = dp.blood[i][j-1]-chess[i][j];
if(dp.blood[i][j] <= 0) {
dp.co[i][j] = 0;
}
}
}else if(dp.co[i-1][j] == 0) {// 有一個爲0取另外一個
dp.co[i][j] = dp.co[i][j-1]+1;
dp.blood[i][j] = dp.blood[i][j-1]-chess[i][j];
if(dp.blood[i][j] <= 0) {
dp.co[i][j] = 0;
}
}else{
dp.co[i][j] = dp.co[i-1][j]+1;
dp.blood[i][j] = dp.blood[i-1][j]-chess[i][j];
if(dp.blood[i][j] <= 0) {
dp.co[i][j] = 0;
}
}
}
}
if(dp.blood[n][n] > 0) {
printf("%d",dp.co[n][n]);
}else {
printf("No");
}
return 0;
}