http://acm.uestc.edu.cn/#/problem/show/381
题目大意:给你两个棋子:车、马,再给你一个n*m的网格,从s出发到t,你可以选择车或者选择马开始走,图中有一些障碍物,该障碍物是不能走的,走的图中有换一次棋子的机会,问最少需要几次能从s走到t?
思路:bfs来4次就好了。两次记录从s->t,两次是t->s。然后暴力一下就出来了,复杂度为4*n*m*log

//看看会不会爆int!数组会不会少了一维! //取物问题一定要小心先手胜利的条件 #include <bits/stdc++.h> using namespace std; #define LL long long #define ALL(a) a.begin(), a.end() #define pb push_back #define mk make_pair #define fi first #define se second #define haha printf("haha ") const int maxn = 100 + 5; const int inf = 0x3f3f3f3f; char ch[maxn][maxn]; int n, m; pair<int, int> s, t; int rook[maxn][maxn], knight[maxn][maxn]; int r1[maxn][maxn], k1[maxn][maxn]; int r2[maxn][maxn], k2[maxn][maxn]; int dx[] = {-2, -2, -1, 1, 2, 2, 1, -1}; int dy[] = {-1, 1, 2, 2, 1, -1, -2, -2}; int bfs1(int a, int b){ memset(rook, 0x3f, sizeof(rook)); queue<pair<int, int> > que; que.push(mk(a, b)); rook[a][b] = 0; while (!que.empty()){ pair<int, int> p = que.front(); que.pop(); int x = p.fi, y = p.se; ///if (flag && x == s.fi && y == s.se) break; int lb = 0, rb = 0; for (int i = x - 1; i > 0; i--) if (ch[i][y] == '#') {lb = i; break;} for (int i = x; i <= n; i++) if (ch[i][y] == '#') {rb = i; break;} if (rb == 0) rb = n + 1; ///lb和rb都是不能走的 for (int i = lb + 1; i < rb; i++){ if (i != x && rook[i][y] > rook[x][y] + 1){ rook[i][y] = rook[x][y] + 1; que.push(mk(i, y)); } } lb = 0, rb = 0; for (int i = y - 1; i > 0; i--) if (ch[x][i] == '#') {lb = i; break;} for (int i = y; i <= m; i++) if (ch[x][i] == '#') {rb = i; break;} if (rb == 0) rb = m + 1; for (int i = lb + 1; i < rb; i++){ if (i != y && rook[x][i] > rook[x][y] + 1){ rook[x][i] = rook[x][y] + 1; que.push(mk(x, i)); } } } return rook[s.fi][s.se]; } int bfs2(int a, int b){ memset(knight, 0x3f, sizeof(knight)); queue<pair<int, int> > que; que.push(mk(a, b)); knight[a][b] = 0; while (!que.empty()){ pair<int, int> p = que.front(); que.pop(); int x = p.fi, y = p.se; ///if (flag && x == s.fi && y == s.se) break; for (int i = 0; i < 8; i++){ int nx = x + dx[i], ny = y + dy[i]; if (nx <= 0 || ny <= 0 || nx > n || ny > m) continue; if (ch[nx][ny] == '#') continue; if (knight[nx][ny] > knight[x][y] + 1){ knight[nx][ny] = knight[x][y] + 1; que.push(mk(nx, ny)); } } } return rook[s.fi][s.se]; } int solve(){ //printf("k = %d r = %d ", k[s.fi][s.se], r[s.fi][s.se]); //int mini = min(r2[t.fi][t.se], k2[t.fi][t.se]); int mini = inf; for (int i = 1; i <= n; i++){ for (int j = 1; j <= m; j++){ if (ch[i][j] == '#') continue; if (r1[i][j] < inf && k2[i][j] < inf) mini = min(mini, r1[i][j] + k2[i][j]); if (k1[i][j] < inf && r2[i][j] < inf) mini = min(mini, k1[i][j] + r2[i][j]); } } if (mini == inf) return -1; return mini; } int main(){ int T; cin >> T; for (int kase = 1; kase <= T; kase++){ cin >> n >> m; for (int i = 1; i <= n; i++){ scanf("%s", ch[i] + 1); for (int j = 1; j <= m; j++){ if (ch[i][j] == 's') s = mk(i, j); if (ch[i][j] == 't') t = mk(i, j); } } memset(r1, inf, sizeof(r1)); memset(k1, inf, sizeof(k1)); memset(r2, inf, sizeof(r2)); memset(k2, inf, sizeof(k2)); bfs1(t.fi, t.se); bfs2(t.fi, t.se); for (int i = 1; i <= n; i++) for (int j = 1; j <= m; j++) r1[i][j] = rook[i][j], k1[i][j] = knight[i][j]; bfs1(s.fi, s.se); bfs2(s.fi, s.se); for (int i = 1; i <= n; i++) for (int j = 1; j <= m; j++) r2[i][j] = rook[i][j], k2[i][j] = knight[i][j]; printf("Case #%d: %d ", kase, solve()); } return 0; }