#include using namespace std; const int N = 110, INF = 0x3f3f3f3f; int n, m; int g[N][N]; // 原始地图 int d[N][N]; // 记录最短距离,这个东西的作用是用来进行最优化剪枝,这个非常妙 int dx[] = {-1, 0, 1, 0}, dy[] = {0, 1, 0, -1}; void dfs(int x, int y, int cost, int used) { if (d[x][y] <= cost) return; // 最优化剪枝,排除非最优路线 d[x][y] = cost; // 记录最优路线花费 if (x == m && y == m) return; // 递归出口 for (int i = 0; i < 4; i++) { int nx = x + dx[i], ny = dy[i] + y; if (nx < 1 || nx > m || ny < 1 || ny > m) continue; if (g[nx][ny] == -1) { // 下一个位置是无色 if (used) continue; // 当前位置已使过魔法,下一个就无法继续使用魔法,无色不能变有色,无效 // 如果当前位置没有使用过魔法的话,下一个位置是可以使用魔法的,那么变成什么颜色呢? // 你可以花费 2 个金币施展魔法让下一个无色格子暂时变为 你当前所处格子的颜色 g[nx][ny] = g[x][y]; dfs(nx, ny, cost + 2, 1); // 走入这个(nx,ny),标识费用+2,同时标注(nx,ny)的魔法是已使用状态,继续传递 g[nx][ny] = -1; // 也可以不走这个(nx,ny),需要回溯 } else if (g[nx][ny] == g[x][y]) // 下一个位置颜色相同 dfs(nx, ny, cost, 0); // 直接走过去,费用不变,也没有使用魔法 else dfs(nx, ny, cost + 1, 0); // 有色到有色,颜色不同,花费1个金币,没有使用魔法 } } int main() { // 加快读入 ios::sync_with_stdio(false), cin.tie(0); cin >> m >> n; memset(g, -1, sizeof g); // 标识无色是-1 while (n--) { int a, b, c; cin >> a >> b >> c; g[a][b] = c; // 有颜色你就说是啥颜色吧 } memset(d, 0x3f, sizeof d); dfs(1, 1, 0, 0); if (d[m][m] == INF) puts("-1"); else cout << d[m][m] << endl; return 0; }