NC23486 小A与小B
题目地址:
基本思路:
我们看题很容易判断出这题能用解决,我这里有两种的方法,总体来说第二种更优。
- 我们初步考虑可不可以进行两次,在第一次过程中记录小A到达每个位置的最短时间,然后在第二次中记录小B到达每个位置的最短时间,最后将小B到达这个位置的时间和小A到达这个位置的时间取最大作为在这个位置的最早相遇时间,最后统计到总体最短相遇时间,这个方法的代码如下,总体复杂度是跑满的。(实际跑了155ms)
参考代码:
#pragma GCC optimize(2) #pragma GCC optimize(3) #include <bits/stdc++.h> using namespace std; #define IO std::ios::sync_with_stdio(false) #define int long long #define rep(i, l, r) for (int i = l; i <= r; i++) #define per(i, l, r) for (int i = l; i >= r; i--) #define mset(s, _) memset(s, _, sizeof(s)) #define pb push_back #define pii pair <int, int> #define mp(a, b) make_pair(a, b) #define INF (int)1e18 inline int read() { int x = 0, neg = 1; char op = getchar(); while (!isdigit(op)) { if (op == '-') neg = -1; op = getchar(); } while (isdigit(op)) { x = 10 * x + op - '0'; op = getchar(); } return neg * x; } inline void print(int x) { if (x < 0) { putchar('-'); x = -x; } if (x >= 10) print(x / 10); putchar(x % 10 + '0'); } const int maxn = 1010; char a[maxn][maxn]; int n,m,dp1[maxn][maxn],dp2[maxn][maxn]; bool vis[maxn][maxn]; int d[8][2] = {{-1, 0}, {0, -1}, {1, 0}, {0, 1}, {-1, 1}, {1, -1}, {-1, -1}, {1, 1}}; signed main() { IO; queue<pii> que1,que2; cin >> n >> m; rep(i,1,n){ rep(j,1,m){ cin >> a[i][j]; dp1[i][j] = dp2[i][j] = INF; if(a[i][j] == 'C') { que1.push({i,j}); dp1[i][j] = 0;} if(a[i][j] == 'D') { que2.push({i,j}); dp2[i][j] = 0;} } } //小A到每个位置的最短时间; while (!que1.empty()){ int x = que1.front().first,y = que1.front().second; que1.pop(); for(int i = 0 ; i < 8 ; i++){ int nx = x + d[i][0],ny = y + d[i][1]; if(nx >= 1 && nx <= n && ny >= 1 && ny <= m && dp1[nx][ny] == INF && a[nx][ny] != '#'){ dp1[nx][ny] = min(dp1[nx][ny],dp1[x][y] + 1); que1.push({nx,ny}); } } } //小B到每个位置的最短时间; while (!que2.empty()){ int x = que2.front().first,y = que2.front().second; que2.pop(); for(int i = 0 ; i < 4 ; i++){ int nx = x + d[i][0],ny = y + d[i][1]; if(nx >= 1 && nx <= n && ny >= 1 && ny <= m && dp2[nx][ny] == INF && a[nx][ny] != '#'){ dp2[nx][ny] = min(dp2[nx][ny],dp2[x][y] + 1); que2.push({nx,ny}); } } } int ans = INF; rep(i,1,n){ rep(j,1,m){ if(dp1[i][j] == INF || dp2[i][j] == INF) continue; //小B每次走两步,所以除二向上取整; int res = max(dp1[i][j],(int)ceil((double)dp2[i][j] / 2.0)); ans = min(ans,res); } } if(ans == INF) cout << "NO" << '\n'; else{ cout << "YES" << '\n'; cout << ans << '\n'; } return 0; }
- 如果说第一种方法类似离线,那么第二种就算是在线的一个,对于每一步我们从小A,和小B两个方向进行双向,对于小A我们每次只走一步也就是一层,而对于小B我们每次两层,在过程中只要出现走过对方走过的路的情况就说明相遇了,这个时候直接结束就能得到答案,总体复杂度是大概率跑不满的。(实际跑了38ms)
参考代码:
#pragma GCC optimize(2) #pragma GCC optimize(3) #include <bits/stdc++.h> using namespace std; #define IO std::ios::sync_with_stdio(false) #define int long long #define rep(i, l, r) for (int i = l; i <= r; i++) #define per(i, l, r) for (int i = l; i >= r; i--) #define mset(s, _) memset(s, _, sizeof(s)) #define pb push_back #define pii pair <int, int> #define mp(a, b) make_pair(a, b) #define INF (int)1e18 inline int read() { int x = 0, neg = 1; char op = getchar(); while (!isdigit(op)) { if (op == '-') neg = -1; op = getchar(); } while (isdigit(op)) { x = 10 * x + op - '0'; op = getchar(); } return neg * x; } inline void print(int x) { if (x < 0) { putchar('-'); x = -x; } if (x >= 10) print(x / 10); putchar(x % 10 + '0'); } const int maxn = 1010; int n,m; char a[maxn][maxn]; bool vis[2][maxn][maxn]; int d[8][2] = {{-1, 0}, {0, -1}, {1, 0}, {0, 1}, {-1, 1}, {1, -1}, {-1, -1}, {1, 1}}; bool fd = false; queue<pii> que[2]; void bfs(int f){ int sz = que[f].size(); while (sz--){ int x = que[f].front().first,y = que[f].front().second; que[f].pop(); for(int i = 0 ; i < (f ? 4 : 8) ; i++){ int nx = x + d[i][0],ny = y + d[i][1]; if(nx >= 1 && nx <= n && ny >= 1 && ny <= m && !vis[f][nx][ny] && a[nx][ny] != '#'){ if(vis[f ^ 1][nx][ny]){ fd = true; return; } // 相遇了; vis[f][nx][ny] = true; que[f].push({nx,ny}); } } } } int solve(){ fd = false; int cnt = 0; while (!que[0].empty() || !que[1].empty()){ cnt++; //小A走一步,小B走两步; bfs(0); bfs(1); bfs(1); if(fd) return cnt; //这一定是最早的相遇时间; } return -1; } signed main() { IO; cin >> n >> m; mset(vis,false); rep(i,1,n){ rep(j,1,m){ cin >> a[i][j]; if(a[i][j] == 'C') { que[0].push({i,j}); vis[0][i][j] = true; } if(a[i][j] == 'D') { que[1].push({i,j}); vis[1][i][j] = true; } } } int ans = solve(); if(ans == -1) cout << "NO" << '\n'; else { cout << "YES" << '\n'; cout << ans << '\n'; } return 0; }