首页 > 其他分享 >Manhattan Triangle

Manhattan Triangle

时间:2024-08-03 21:54:46浏览次数:5  
标签:Triangle Manhattan 比雪夫 距离 mark vis last find

纪念一下代码打得太慢了导致比赛结束3分钟才做出来的E题

我的做法:

考虑确定枚举三角形的一个点。最开始尝试枚举\(x\)最大的点,但是后面发现不太好讨论,于是尝试枚举\(x\)在中间的点,此时发现由于曼哈顿是三角形不可能是钝角三角形,剩下两个点要么同时在中间点的上方,要么同时在中间点的下方

形式化地,设三个点分别为 \((x_1,y_1),(x_2,y_2),(x_3,y_3)\) ,其中 \(x_1≤x_2≤x_3\) , 那么有 \(y_1≤y_2\) 且 \(y_3≤y_2\) 或者 \(y_1≥y_2\) 且 \(y_3≥y_2\)

我们讨论一种情况: \(y_1≤y_2\) 且 \(y_3≤y_2\) , 另一种情况同理

可知这种情况又可分为两种情况, \(y_2≤y_3\) 或者 \(y_3≤y_2\) , 我们仍然讨论第一种情况,另一种情况同理

画图:

我们发现,有长方形的周长为 \(3d\) , 于是长加宽为 \(\frac{3d}{2}\) , 也就是 \(AF+AC=\frac{3d}{2}\) , 而我们有 \(AF+AB=d\) , 于是有 \(BC=\frac{d}{2}\), 又因为 \(BC+CD=d\) , 于是 \(DC=\frac{d}{2}\)

所以我们发现,我们枚举了中间点之后,可以直接确定 \(x\) 最大的点,现在只用确定最后一个点就好了

不难有 \(x_2-x_1+y_2-y_1=d\) , 即 \(x_2+y_2-d=x_1+y_1\) , 或者 \(x_3+y_3-d=x_1+y_1\)

一个比较自然的想法是我们用一个数据结构记录 \(x<x_2\) 的所有点,然后直接查找就好了。但是这样会出现一个问题,就是如果我们查找出来的点的纵坐标大于\(y_3\)怎么办?实际上如果采用一些小技巧,就不会出现这种情况。我们发现 \(AC≤d\) , 所以 \(AB≤\frac{d}{2}\) , 如果我们只保存横坐标在 \(AB\) 范围内的点,那么此时对数据结构中任意一个点 \((x,y)\) , 有 \(x_3-x≤d\) , 如果\(y>y_3\) ,那么 \(y_3+x_3-x<d+y\) , 也就是 \(y_3+x_3-d<x+y\) ,不可能满足上面的等式,所以不用担心

于是这种情况就处理完了,其余情况类似处理

代码(代码能力比较弱,不会写函数封装,所以比较丑;实际上以上思路来自《算法竞赛进阶指南》CDQ分治的例题的代码,用的是函数封装):

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=2e5+10;
int n,d;
struct Point
{
	int x,y,id;
}p[N];
map<pair<int,int>,int> mark;
map<int,queue<int> > vis;//注意这里要用队列存储所有满足条件的点
bool cmp(Point a,Point b)
{
	if(a.x==b.x)return a.y<b.y;
	return a.x<b.x;
}
bool cmp1(Point a,Point b)
{
	if(a.x==b.x)return a.y>b.y;
	return a.x<b.x;
}
bool cmp2(Point a,Point b)
{
	if(a.x==b.x)return a.y<b.y;
	return a.x>b.x;
}
bool cmp3(Point a,Point b)
{
	if(a.x==b.x)return a.y>b.y;
	return a.x>b.x;
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
    	mark.clear();
    	scanf("%d%d",&n,&d);
    	for(int i=1;i<=n;i++)
    	{
    		scanf("%d%d",&p[i].x,&p[i].y);
    		p[i].id=i;
    		mark[make_pair(p[i].x,p[i].y)]=i;
		}
		bool flag=0;
		vis.clear();
    	sort(p+1,p+n+1,cmp);
    	p[0].x=-1e6;
    	for(int i=1,last=1;i<=n;i++)
    	{
    		if(p[i].x!=p[i-1].x)
    		while(p[last].x<p[i].x-(d>>1)) 
			{
				vis[p[last].x+p[last].y].pop();
				if(vis[p[last].x+p[last].y].empty())
				{
					map<int,queue<int> >::iterator it=vis.find(p[last].x+p[last].y);
					vis.erase(it);
				}
				last++;
			}
    		if(mark.find(make_pair(p[i].x+(d>>1),p[i].y-(d>>1)))!=mark.end()&&vis.find(p[i].x+p[i].y-d)!=vis.end())
    		{
    			flag=1;
    			printf("%d %d %d\n",p[i].id,mark[make_pair(p[i].x+(d>>1),p[i].y-(d>>1))],vis[p[i].x+p[i].y-d].front());
    			break;
			}
			vis[p[i].x+p[i].y].push(p[i].id);
		}
		if(flag) continue;
		vis.clear();
    	sort(p+1,p+n+1,cmp1);
    	p[0].x=-1e6;
    	for(int i=1,last=1;i<=n;i++)
    	{
    		if(p[i].x!=p[i-1].x)
    		while(p[last].x<p[i].x-(d>>1)) 
			{
				vis[p[last].y-p[last].x].pop();
				if(vis[p[last].y-p[last].x].empty())
				{
					map<int,queue<int> >::iterator it=vis.find(p[last].y-p[last].x);
					vis.erase(it);
				}
				last++;
			}
    		if(mark.find(make_pair(p[i].x+(d>>1),p[i].y+(d>>1)))!=mark.end()&&vis.find(-p[i].x+p[i].y+d)!=vis.end())
    		{
    			flag=1;
    			printf("%d %d %d\n",p[i].id,mark[make_pair(p[i].x+(d>>1),p[i].y+(d>>1))],vis[-p[i].x+p[i].y+d].front());
    			break;
			}
			vis[-p[i].x+p[i].y].push(p[i].id);
		}
		if(flag) continue;
		vis.clear();
    	sort(p+1,p+n+1,cmp2);
    	p[0].x=1e6;
    	for(int i=1,last=1;i<=n;i++)
    	{
    		if(p[i].x!=p[i-1].x)
    		while(p[last].x>p[i].x+(d>>1)) 
			{
				vis[-p[last].y+p[last].x].pop();
				if(vis[-p[last].y+p[last].x].empty())
				{
					map<int,queue<int> >::iterator it=vis.find(-p[last].y+p[last].x);
					vis.erase(it);
				}
				last++;
			}
    		if(mark.find(make_pair(p[i].x-(d>>1),p[i].y-(d>>1)))!=mark.end()&&vis.find(p[i].x-p[i].y+d)!=vis.end())
    		{
    			flag=1;
    			printf("%d %d %d\n",p[i].id,mark[make_pair(p[i].x-(d>>1),p[i].y-(d>>1))],vis[p[i].x-p[i].y+d].front());
    			break;
			}
			vis[p[i].x-p[i].y].push(p[i].id);
		}
		if(flag) continue;
		vis.clear();
    	sort(p+1,p+n+1,cmp3);
    	p[0].x=1e6;
    	for(int i=1,last=1;i<=n;i++)
    	{
    		if(p[i].x!=p[i-1].x)
    		while(p[last].x>p[i].x+(d>>1)) 
			{
				vis[p[last].y+p[last].x].pop();
				if(vis[p[last].y+p[last].x].empty())
				{
					map<int,queue<int> >::iterator it=vis.find(p[last].y+p[last].x);
					vis.erase(it);
				}
				last++;
			}
    		if(mark.find(make_pair(p[i].x-(d>>1),p[i].y+(d>>1)))!=mark.end()&&vis.find(p[i].x+p[i].y+d)!=vis.end())
    		{
    			flag=1;
    			printf("%d %d %d\n",p[i].id,mark[make_pair(p[i].x-(d>>1),p[i].y+(d>>1))],vis[p[i].x+p[i].y+d].front());
    			break;
			}
			vis[p[i].x+p[i].y].push(p[i].id);
		}
		if(!flag) puts("0 0 0");
	}
    return 0;
}

然后讲一下题解区说的曼哈顿距离转切比雪夫距离(蒟蒻以前没听过这个trick,学了一下,给没见过的同学看看)

将曼哈顿距离(Manhattan Distance)转化为切比雪夫距离(Chebyshev Distance)可以通过一种简单的坐标变换来实现。这种变换基于两者之间的数学关系,使得在变换后的坐标系中,曼哈顿距离等价于切比雪夫距离。

曼哈顿距离

曼哈顿距离定义为在标准的坐标系上,两个点在标准坐标系上的绝对轴距总和。对于二维空间中的两个点 $ P_1(x_1, y_1) $ 和 $ P_2(x_2, y_2) $,曼哈顿距离 $ D_M $ 定义为:

\[D_M(P_1, P_2) = |x_1 - x_2| + |y_1 - y_2| \]

切比雪夫距离

切比雪夫距离定义为两个点在向量空间中的各坐标数值差绝对值的最大值。对于二维空间中的两个点 $ P_1(x_1, y_1) $ 和 $ P_2(x_2, y_2) $,切比雪夫距离 $ D_C $ 定义为:

\[D_C(P_1, P_2) = \max(|x_1 - x_2|, |y_1 - y_2|) \]

坐标变换

为了将曼哈顿距离转化为切比雪夫距离,我们可以对原始坐标进行缩放和旋转(在二维情况下,实际上是通过缩放实现的,因为旋转不会改变曼哈顿距离和切比雪夫距离的等价性)。但是,更直接的方法是使用一种称为“等距嵌入”的技巧,即通过一个线性变换将原坐标系映射到一个新的坐标系中,使得在新的坐标系中曼哈顿距离等于切比雪夫距离。

具体来说,对于二维空间中的点,我们可以将每个点的坐标 \((x, y)\) 映射为 \((x+y, x-y)\)(注意,这不是唯一的映射方式,但它是有效的一种)。在新的坐标系中,两点之间的曼哈顿距离将等于它们之间的切比雪夫距离。

证明

设 $ P_1(x_1, y_1) $ 和 $ P_2(x_2, y_2) $ 在新坐标系中对应的点为 $ P_1'(x_1+y_1, x_1-y_1) $ 和 $ P_2'(x_2+y_2, x_2-y_2) $。

在新坐标系中,两点之间的切比雪夫距离为:

\[D_C'(P_1', P_2') = \max(|(x_1+y_1) - (x_2+y_2)|, |(x_1-y_1) - (x_2-y_2)|) \]

这可以简化为:

\[D_C'(P_1', P_2') = \max(|x_1 - x_2 + y_1 - y_2|, |x_1 - x_2 - y_1 + y_2|) \]

由于 $ |a+b| \leq |a| + |b| $ 和 $ |a-b| \leq |a| + |b| $,我们可以得出:

\[\max(|x_1 - x_2 + y_1 - y_2|, |x_1 - x_2 - y_1 + y_2|) \leq |x_1 - x_2| + |y_1 - y_2| \]

但在这种情况下,等号成立,因为:考虑 $ |a+b| \leq |a| + |b| $ 和 $ |a-b| \leq |a| + |b| $ 的取等条件,若 \(a,b\)符号相同则前者取等,否则后者取等,于是讨论 \(|x_1 - x_2|\) 和 \(|y_1 - y_2|\)的符号就可以知道等号成立

以上内容来自文心一言,最后的证明稍作修改

于是进行坐标变换之后可以知道这道题目转化为:找出三个点 \((x_1,y_1),(x_2,y_2),(x_3,y_3)\) , 使得 \(\max(|x_1-x_2|,|y_1-y_2|)=\max(|x_1-x_3|,|y_1-y_3|)=\max(|x_2-x_3|,|y_2-y_3|)=d\) ,分类讨论,不妨设 \(x_1≤x_2≤x_3\) , 如果说 \(|x_1-x_3|<d\) , 那么就有三个点的\(y\)两两距离都为 \(d\) , 这显然不可能,所以有 \(x_3-x_1=d\) , 同理讨论可以知道 \(y_1=y_3\) , 于是随便用数据结构维护一下就好了

标签:Triangle,Manhattan,比雪夫,距离,mark,vis,last,find
From: https://www.cnblogs.com/dingxingdi/p/18341175

相关文章

  • [USACO1.5] [IOI1994]数字三角形 Number Triangles
    传送锚点[P1216USACO1.5][IOI1994]数字三角形NumberTriangles-洛谷|计算机科学教育新生态(luogu.com.cn)题目[USACO1.5][IOI1994]数字三角形NumberTriangles题目描述观察下面的数字金字塔。写一个程序来查找从最高点到底部任意处结束的路径,使路径经过数字的和最......
  • 题解:AT_arc173_b [ARC173B] Make Many Triangles
    背景前几天打了比赛,崩麻了,所以来水一篇题解。LC真睿智题意给你\(n\)个点,问最多能组成几个三角形。分析听说可以随机化。这道题就是一个简单贪心。我们考虑,如果没有共线的点,那么答案显然就是\(\frac{n}{3}\)了。如果有共线,我们容易想到一个贪心思路:既然同一直线上的点不......
  • C. Count Triangles
    原题链接题解我们知道,三角形成立的条件是任意两边之和都要大于第三边,因为这里已经明确了三条边的大小关系,即\(x\leqy\leqz\)所以,该三角形成立的条件是\(x+y>z\)看到\(5e5\)我们不难想到遍历其中某条边的长度这里我遍历的是\(y\)遍历\(y\),找到最小的\(x\)使得至少......
  • CF1979E Manhattan Triangle
    题目描述给定\(n\)个点,找出三个点使得这三个点两两之间的曼哈顿距离为偶数\(d\)\[n\le300000\]题解与一个点的曼哈顿距离为\(d\)的点是一个斜\(45°\)的正方形设这个点坐标为\((x,y)\)考虑另外两个点可能在哪些位置,如果另外两个点在正方形的同一条边上,那么这两个点的横纵......
  • LeetCode //C - 119. Pascal‘s Triangle II
    119.Pascal’sTriangleIIGivenanintegerrowIndex,returntherowIndexth(0-indexed)rowofthePascal’striangle.InPascal’striangle,eachnumberisthesumofthetwonumbersdirectlyaboveitasshown: Example1:Input:rowIndex=3Outpu......
  • Games101-3 triangle
    rasterize==drawingontothescreencolor=(red,green,blue)pixelindicesarefrom(0,0)to(width-1,height-1)pixel(x,y)iscenteredat(x+0.5,y+0.5)光栅化判断一个像素的中心点是否需要draw采样的方法--将函数离散化如果中心再三角形内。如何判断......
  • AoPS - Chapter 3 More Triangles
    本章主要讲解正弦定理、余弦定理、海伦公式、Stewart'sTheorem。本文在没有特殊说明时,默认在\(\triangleABC\)中:\(a\)为角\(A\)对边,\(b\)为角\(B\)对边,\(c\)为角\(C\)对边。\(r\)为内切圆半径(inradius),\(R\)为外接圆半径(circumradius)。\([ABC]\)为\(\triangl......
  • 题解:CF1337A Ichihime and Triangle
    看到大佬们基本都是直接输出\(b\)\(c\)\(c\)了事儿,一身反骨有其它构造方法的我表示不服,遂作此篇。众所周知,两边之和大于第三边,所以,如果\(b+c>d\),那么\(b\)、\(c\)、\(d\)就是正确的。那如果不满足呢?在题目条件下\(b+c>b+c-1\),那么这一组就是合理的。分别验......
  • 【计算几何】Triangle Cillision 三角碰撞 [模型转化][二分]
    题意给定一个边长为L的三角形和一个直径非常微小的球,问球在三角形内与三角形的边第k次碰撞的时间思路模型转化:将碰撞转化为穿越二分查找时间code:#include<bits/stdc++.h>usingnamespacestd;constdoubleeps=1e-7;#defineendl"\n"#defineintlonglongstructPoi......
  • P4423 / YC271A [ 20240411 CQYC省选模拟赛 T1 ] 三角形(triangle)
    题意给定\(n\)个点,求平面最小三角形周长。Sol其实挺简单一算法,一直没学。先随机转个∠,然后按照\(x\)排序。考虑分治。注意到分治左右两边的答案对当前可用的区间有限制。将满足限制的点按照\(y\)排序。这里可以归并做到一只\(log\)。然后集中注意力,发现对于每个点......