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;
}

京公网安备 11010502036488号