题意:有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;
}