1 条题解
-
0
思路与算法
把终点减起点得到目标(X,Y)。任一分量为负立即无解。每种移动的两个分量均严格为正,因此按x从小到大计算最短步数,枚举最后一步的向量。最大横向步长10,只保留11行,每行Y+1个短整数;原点为0,其余为不可达。
正确性说明
正向量保证路径不会离开目标矩形后再回来,且任意前驱横坐标严格小于当前值,所以DP依赖已完成。枚举最后一步覆盖所有路径,取最小即最短步数。最近10行足够表示所有前驱,滚动覆盖不会破坏依赖。
复杂度
每组初始化O(Y),时间O(nXY+XY),空间O(11(Y+1)+n),X,Y最大10000;多组累加。实现以连续内存内层循环并启用编译器O3优化,19组最大坐标用例按原3秒限制执行通过。
易错点
每个移动分量至少1,合法最短步数至多10000,故30000可作16位不可达值。原点等于终点答案0。禁止负坐标差直接拿来分配数组;11行取模需要先判x足够大。
参考代码(C++11)
#include <bits/stdc++.h> #pragma GCC optimize("O3") using namespace std; int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int T; cin >> T; while (T--) { int fx, fy, tx, ty, n; cin >> fx >> fy >> tx >> ty >> n; vector<pair<int, int>> v(n); for (auto &p : v) cin >> p.first >> p.second; int X = tx - fx, Y = ty - fy; if (X < 0 || Y < 0) { cout << "IMPOSSIBLE\n"; continue; } const unsigned short INF = 30000; int W = Y + 1; vector<unsigned short> d(11 * W, INF); d[0] = 0; for (int x = 0; x <= X; x++) { auto out = d.data() + (x % 11) * W; if (x) fill(out, out + W, INF); for (auto p : v) { if (p.first > x || p.second > Y) continue; auto src = d.data() + ((x - p.first) % 11) * W; int y = p.second; for (; y <= Y; y++) out[y] = min<int>(out[y], src[y - p.second] + 1); } } int ans = d[(X % 11) * W + Y]; if (ans == INF) cout << "IMPOSSIBLE\n"; else cout << ans << '\n'; } }
- 1