题意: 在一个 n * m 的地图里,有 k 个宝藏,你的起点在 (1, 1), 每次你能 向下向右向左移动(只要在地图里);
现在,有 q 个安全的列, 你只有在这些列上面,你才能向下走。 问你收集所有宝藏,需要走的最少步数
解: 首先,我们对每一行 维护数组 L, R,分别代表 这一行的所有宝藏中,最左的那个和最右的那个的 纵坐标
然后 维护两个值 ansl, ansr 分别代表你处理完前 i 行所有的宝藏都拿完了之后;
停在 L[ i ], 和停在 R[ i ]处的最小步数;
那么你更新 ansl, ansr 各有四种情况; ( 代码有提到,详见代码)
然后处理完N行后, 去 ansl, ansr 较小的那个,就是所有横向需要走的最小步数。
然后纵向的话,你走的步数就是 所有宝藏中最大的 x - 1 步;
然后相加就是答案了。
#include <iostream> #include <cstdio> #include <fstream> #include <algorithm> #include <cmath> #include <deque> #include <vector> #include <queue> #include <string> #include <cstring> #include <map> #include <stack> #include <set> #define LL long long #define ULL unsigned long long #define rep(i,j,k) for(int i=j;i<=k;i++) #define dep(i,j,k) for(int i=k;i>=j;i--) #define INF 0x3f3f3f3f3f3f3f3f #define mem(i,j) memset(i,j,sizeof(i)) #define make(i,j) make_pair(i,j) #define pb push_back #define Pi acos(-1.0) using namespace std; const int N = 2e5 + 5; LL l[N], r[N], s[N]; int main() { int n, m, k, q; while(~scanf("%d %d %d %d", &n, &m, &k, &q)) { rep(i, 1, n) l[i] = INF, r[i] = 0; LL Y = 0; rep(i, 1, k) { LL x, y; scanf("%lld %lld", &x, &y); Y = max(Y, x); l[x] = min(l[x], y); r[x] = max(r[x], y); } rep(i, 1, q) scanf("%lld", &s[i]); sort(s + 1, s + 1 + q); LL ansl, ansr; LL L = l[1], R = r[1]; if(r[1] == 0) ansl = 0, ansr = 0, L = R = 1; else ansl = r[1] - 1 + r[1] - l[1], ansr = r[1] - 1; rep(i, 2, n) if(r[i]) { int indexl = lower_bound(s + 1, s + 1 + q, L) - s; int indexr = lower_bound(s + 1, s + 1 + q, R) - s; int Ll, Lr, Rl, Rr; Ll = Lr = Rl = Rr = INF; if(indexl <= q) Lr = s[indexl]; if(indexl > 1) Ll = s[indexl - 1]; if(indexr <= q) Rr = s[indexr]; if(indexr > 1) Rl = s[indexr - 1]; LL nowL = INF, nowR = INF; nowL = min(nowL, ansl + abs(L - Ll) + abs(Ll - r[i]) + abs(r[i] - l[i])); ///L -> Ll -> r[i] -> l[i] nowL = min(nowL, ansl + abs(L - Lr) + abs(Lr - r[i]) + abs(r[i] - l[i])); ///L -> Lr -> r[i] -> l[i] nowL = min(nowL, ansr + abs(R - Rl) + abs(Rl - r[i]) + abs(r[i] - l[i])); ///R -> Rl -> r[i] -> l[i] nowL = min(nowL, ansr + abs(R - Rr) + abs(Rr - r[i]) + abs(r[i] - l[i])); ///R -> Rr -> r[i] -> l[i] nowR = min(nowR, ansl + abs(L - Ll) + abs(Ll - l[i]) + abs(l[i] - r[i])); ///L -> Ll -> l[i] -> r[i] nowR = min(nowR, ansl + abs(L - Lr) + abs(Lr - l[i]) + abs(l[i] - r[i])); ///L -> Lr -> l[i] -> r[i] nowR = min(nowR, ansr + abs(R - Rl) + abs(Rl - l[i]) + abs(l[i] - r[i])); ///R -> Rl -> l[i] -> r[i] nowR = min(nowR, ansr + abs(R - Rr) + abs(Rr - l[i]) + abs(l[i] - r[i])); ///R -> Rr -> l[i] -> r[i] ansl = nowL, ansr = nowR; L = l[i], R = r[i]; } printf("%lld ", min(ansl, ansr) + Y - 1); } return 0; }