所有的点可以分成两种情况
①.该点上下左右四个位置存在合法的点,合法指的是不出现在题目给的n个点中。
②.该点上下左右四个位置的点都不合法。
对于第一种情况,答案就是周围的任意一个合法 的点,第二种情况答案就是离它最近的一个且周围有合法点的点\(p\),\(p\)的答案就是它的答案。
所以我们可以进行\(BFS\),先把最外围的点(第一种情况的点)加入到队列里面,然后利用队列里面的点\(q\)不断更新上下左右四个方向的点,如果这个点\(p\)在给的\(n\)个点中,就把\(q\)答案赋给\(p\),然后把\(p\)加入到队列里面继续更新其他的点,这样能保证所有\(n\)个点都能被更新到最小的合法的答案(证明:第一种的点一定会计算出合法答案, 对第二种点来说, 他的周围上下左右四个方向都有题目给的点,所以我们对队列中每个点进行四个方向 的更新,一定能更新到每个题目中给的点,因为是不断的进行上下左右四个方向的更新,所以答案一定保证是最小的)。
#include <bits/stdc++.h>
#define PII pair<int,int>
#define LL long long
#define fi first
#define debug(x) cout << #x << " = " << x << endl;
#define se second
#define all(x) (x).begin(),(x).end()
#define pb push_back
#define sz(x) (int)x.size()
using namespace std;
const int N = 200010;
struct node{
int x, y;
}a[N],ans[N];
bool vis[N];
int n;
map<PII,int>mp;
int dx[] = {0, 0, -1, 1}, dy[] = {1, -1, 0, 0};
int main()
{
cin >> n;
for(int i = 1; i <= n; i ++ ){
int x, y;
scanf("%d %d",&x, &y);
mp[{x, y}] = i;
a[i] = {x, y};
}
queue<int>q;
for(int i = 1; i <= n; i ++ ){
int x = a[i].x, y = a[i].y;
for(int i = 0; i < 4; i ++ ){
int nx = x + dx[i], ny = y + dy[i];
if(!mp.count({nx, ny}) && !vis[mp[{x, y}]]){
vis[mp[{x, y}]] = true;
ans[mp[{x, y}]] = {nx, ny};
// cout << mp[{x, y}] << endl;
q.push(mp[{x, y}]);
}
}
}
// debug(q.size());
while(!q.empty()){
int t = q.front();
q.pop();
int x = a[t].x, y = a[t].y;
for(int i = 0; i < 4; i ++ ){
int nx = x + dx[i], ny = y + dy[i];
int xx = mp[{nx, ny}];
if(vis[xx] || !mp.count({nx, ny})) continue;
q.push(xx);
vis[xx] = true;
ans[xx] = ans[t];
}
}
for(int i = 1; i <= n; i ++ ){
cout << ans[i].x << " " << ans[i].y << endl;
}
return 0;
}