D. Nearest Excluded Points(BFS)

该编程问题要求在给定的平面坐标点集合中,对每个点找出最近的整数坐标点,使用曼哈顿距离作为度量标准。解决方案通过广度优先搜索(BFS)策略,从每个点的相邻整数坐标开始,逐步探索并更新最近的点,确保答案在特定范围内。
摘要由CSDN通过智能技术生成

Problem - D - Codeforces

已知平面上n个不同的点。第i个点的坐标为(æi, yi)。对于每个点i,找到在给定的n个点中最近的整数坐标点(以曼哈顿距离为单位)。如果有多个这样的点,你可以选择其中任何一个。两点(21,91)和(22,92)之间的曼哈顿距离为21 - 22l + ly1 - 92l输入输入的第一行包含一个整数n (1 < n < 2·105)-集合中的点的数量。下面的n条线描述点。第i个包含两个整数æ;和y;(1 S 2i, yi < 2 - 105) -第i个点的坐标。它保证输入中的所有点都是不同的。输出打印n行。在第i行中,打印一个整数坐标的点,它不在给定的n个点中,并且是距离输入的第i个点最近的点(根据曼哈顿距离)。输出坐标应该在范围[-10;10°)。可以证明,任何最优答案都满足这些约束条件。如果有几个答案,您可以打印其中任何一个。

Examples

input

Copy

6
2 2
1 2
2 1
3 2
2 3
5 5

output

Copy

1 1
1 1
2 0
3 1
2 4
5 4

input

Copy

8
4 4
2 4
2 2
2 3
1 4
4 2
1 3
3 3

output

Copy

4 3
2 5
2 1
2 5
1 5
4 1
1 2
3 2

 题解:

1.如果一个点的四周如果有一个点没有点,那么这个点就是离他最近的,这种情况比较好想,

2.那么对于四周都有点包围的点呢,答案应该为从最外层,到他最近的点

换而言之,答案应该包含在我们由1求的点中,不断向内部bfs,只遍历题中出现过的点,

具体细节,代码中有注释

#include<iostream>
#include<algorithm>
#include<string>
#include<cstring>
#include<vector>
#include<map>
#include<queue>
#include<set>
using namespace std;
#define int long long
const int N = 4e5 + 10;
typedef pair<int, int> PII;
int n,k;
int dx[4] = {0,-1,0,1};
int dy[4] = {-1,0,1,0}; 
void solve() 
{
	cin >> n;
	vector <PII> a(n);
	for(int i = 0;i < n;i++)
	{
		int x,y;
		cin >> x >> y;
		a[i] = {x,y};;
	} 
	set <PII> st(a.begin(),a.end());
	map<PII,PII> ans;
	queue<PII> q;
	for(int i = 0;i < n;i++)
	{
		for(int j = 0;j < 4;j++)
		{
			int tx = a[i].first + dx[j];
			int ty = a[i].second + dy[j];
			if(st.count({tx,ty}))
			{
				continue;
			}
			ans[{a[i].first,a[i].second}] = {tx,ty};
			q.push({a[i].first,a[i].second});//把已经求出答案的点存进队列,与他们代表点集合的最外层
			break;
		}
	}
	while(q.size())
	{
		PII t = q.front();
		q.pop();
		for(int i = 0;i < 4;i++)
		{
			int tx = t.first + dx[i];
			int ty = t.second + dy[i];
			if(ans.count({tx,ty}) || !st.count({tx,ty}))
			{
//st代表如果遍历过程中超出规定范围要停下,因为点集内部被包围的点,四周肯定是被标记过的,没被标记,肯定是跑歪了
//ans代表此时走到的点,在之前已经出现过了,既然是第二次遍历,那么点肯定不是最近的
				continue;
			}
			ans[{tx,ty}] = ans[{t.first,t.second}];//由上一个点的状态转移过来,递归下来,答案为最外层某个点存的答案
			q.push({tx,ty});
		}
	}
	for(int i = 0;i < n;i++)
	{
		cout <<ans[a[i]].first <<" "<<ans[a[i]].second<<"\n";
	}
}

//1 2 4
signed main() 
{
//	ios::sync_with_stdio(0);
//	cin.tie(0);cout.tie(0);
	int t = 1;
//	cin >> t;
//scanf("%lld",&t);
	while (t--) 
	{
		solve();
	}
}
//1 1 1 0 1

//1 1 1 0 1
//1 1 1 0 1
//1 1 1 0 1
//0 1 1 1 1
//0 1 1 1 1

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值