题目
在平面上给你 n 个不同的点。第 i 个点的坐标是 (xi,yi)。
对于每个点 i,找到不属于给定 n 个点的整数坐标最近的点(根据曼哈顿距离)。如果有多个这样的点 - 您可以选择其中任何一个。
两点 (x1,y1) 和 (x2,y2) 之间的曼哈顿距离为 |x1−x2|+|y1−y2|。
输入
输入的第一行包含一个整数 n (1≤n≤2⋅105) — 集合中的点数。
接下来的 n 行描述点。其中第 i 个包含两个整数 xi 和 yi (1≤xi,yi≤2⋅105) — 第 i 个点的坐标。
保证输入中的所有点都是不同的。
输出
打印 n 行。在第 i 行中,打印具有整数坐标的点,该点不在给定的 n 个点中,并且距离输入的第 i 个点最近(根据曼哈顿距离)。
输出坐标应在 [−106;106] 范围内。可以证明,任何最优答案都满足这些约束。
如果有多个答案,您可以打印其中任何一个。
题解思路
逆向的想
题目中的点形成的轮廓上的点的答案,肯定是它附近的不是题目中点的点,所以我们先处理这一部分的点,再让这一部分的点来处理不是轮廓上的点(即被包在里面的点),又有bfs一层一层的特性,所以一开始出来的就是答案。
再用更新出来的点继续往前更新,这样我们只会搜到题目要求的n个点,加上map标记复杂度Nlogn。
思维拉满的好题。
AC代码
#include <bits/stdc++.h>
//#include <unordered_map>
//priority_queue
#define PII pair<int,int>
#define ll long long
using namespace std;
const int INF = 0x3f3f3f3f;
const int N = 200100;
int n ;
int dx[4] = {0,0,-1,1} ;
int dy[4] = {1,-1,0,0} ;
map <PII,int> mp ;
map <PII,int> dis ;
map <PII,PII> ans ;
PII a[N] ;
void solve()
{
cin >> n ;
queue <PII> q ;
for (int i = 1 ; i <= n ; i++ )
{
int t1 , t2 ;
cin >> t1 >> t2 ;
mp[{t1,t2}] = 1 ;
a[i] = {t1,t2} ;
}
for (int i = 1 ; i <= n ; i++ )
{
for (int j = 0 ; j < 4 ; j++ )
{
int fx = a[i].first + dx[j] ;
int fy = a[i].second + dy[j] ;
if ( !mp[{fx,fy}] )
{
dis[a[i]] = 1 ;
ans[a[i]] = {fx,fy} ;
q.push(a[i]) ;
break ;
}
}
}
while (!q.empty())
{
auto sk = q.front() ;
q.pop() ;
for (int i = 0 ; i < 4 ; i++ )
{
int fx = sk.first + dx[i] ;
int fy = sk.second + dy[i] ;
if ( mp[{fx,fy}] && !dis[{fx,fy}] )
{
dis[{fx,fy}] = 1 ;
q.push({fx,fy}) ;
ans[{fx,fy}] = ans[sk] ;
}
}
}
for (int i = 1 ; i <= n ; i++ )
{
cout << ans[a[i]].first << " " << ans[a[i]].second << "\n" ;
}
}
int main()
{
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
solve() ;
return 0 ;
}