题意:有N层楼,每层楼M个房间,每层楼的位置0和M+1代表楼梯,1代表亮着灯,上下楼需要1分钟,房间之间移动需要1分钟,初始位置在左下角,问最少多少分钟能关闭所有灯。
dp[i][0] 表示到达第i层左边楼梯所需要的最少时间
dp[1][1] 表示到达第i层右边楼梯所需要的最少时间
L[i] 表示距离左边楼梯最远亮着的灯
R[i] 表示距离右边楼梯最远亮着的灯
思路:对于每一层的左右楼梯维护到达该楼梯所需要的最少需要的时间。
如果该层没有房间亮着:
(可以从左边楼梯直接上来,或者从右边楼梯走m + 2分钟走过来)
dp[i][0] = min(dp[i + 1][0] + 1, dp[i + 1][1] + 2 + m)
(可以从右边楼梯直接上来,或者从左边楼梯走m + 2分钟走过来)
dp[i][1] = min(dp[i + 1][0] + 2 + m, dp[i + 1][1] + 1)
如果该层有房间亮着:
dp[i][0] = min(dp[i + 1][0] + (L[i] - 1) * 2 + 1, dp[i + 1][1] + 2 + m)
dp[i][1] = min(dp[i + 1][0] + 2 + m, dp[i + 1][1] + (2 + m - R[i]) * 2 + 1)
#include <bits/stdc++.h>
using namespace std;
const int maxn = 2005;
int dp[maxn][2];
int L[maxn], R[maxn];
char str[maxn];
int main() {
int n, m;
cin >> n >> m;
for (int i = 1; i <= n; i++) {
cin >> str + 1;
L[i] = 1; R[i] = m + 2;
for (int j = 1; j <= m + 2; j++) {
if (str[j] == '1') L[i] = j;
}
for (int j = m + 2; j >= 1; j--) {
if (str[j] == '1') R[i] =j;
}
}
memset(dp, 60, sizeof(dp));
dp[n][0] = 0; dp[n][1] = m + 1;
dp[n + 1][0] = -1;
for (int i = n; i >= 1; i--) {
if (L[i] != 1) {
dp[i][0] = min(dp[i + 1][0] + (L[i] - 1) * 2 + 1, dp[i + 1][1] + m + 2);
dp[i][1] = min(dp[i + 1][0] + 2 + m, dp[i + 1][1] + (m + 2 - R[i]) * 2 + 1);
} else {
dp[i][0] = min(dp[i + 1][0] + 1, dp[i + 1][1] + m + 2);
dp[i][1] = min(dp[i + 1][1] + 1, dp[i + 1][0] + m + 2);
}
}
int ans = 1e9;
for (int i = 1; i <= n; i++) {
if (L[i] != 1) {
ans = min(dp[i + 1][0] + L[i], dp[i + 1][1] + (m + 2 - R[i] + 1));
cout << ans << endl; return 0;
}
}
cout << "0" << endl;
return 0;
} 
京公网安备 11010502036488号