【模板/經典題型】閔可夫斯基和


閔可夫斯基和,是兩個歐幾里得空間的點集的和,以德國數學家閔可夫斯基命名。
點集A與B的閔可夫斯基和就是{o|o=a+b},其中a屬於A,b屬於B。

對於凸包這種特殊的圖形,它的閔可夫斯基和有一些較好的性質。
比如:凸包之間的閔可夫斯基和一定是凸包。

求凸包之間的閔可夫斯基和的方法。
把兩個凸包的每一條向量都摳出來,按照極角序排序構成新凸包即可。
注意點和向量的去重(向量相同斜率去重)。
還有個地方可以提一下:求多個凸包的閔可夫斯基和的時候可以直接全把邊拿出來一塊求,沒有必要兩個兩個求。
具體實現的時候,找出最高且最靠左的點。
先把這個點加入答案,從這個點開始把所有向量遍歷一遍,最后去掉最后一個點即可(最后這個點會和第一個點重合)。
下面是C++的代碼實現:

	pot P={-inf,-inf},Q={-inf,-inf},R={-inf,-inf};
	n=read(); 
	for(int i=1;i<=n;i++)
	{
		a[i].x=read();a[i].y=read();
		if(dcmp(a[i].y-P.y)==0&&dcmp(a[i].x-P.x)<0)P=a[i];
		if(dcmp(a[i].y-P.y)>0)P=a[i];
		if(i!=1)f[++cnt]=a[i]-a[i-1];if(i==n)f[++cnt]=a[1]-a[i];
	}
	n=read();
	for(int i=1;i<=n;i++)
	{
		b[i].x=read();b[i].y=read();
		if(dcmp(b[i].y-Q.y)==0&&dcmp(b[i].x-Q.x)<0)Q=b[i];
		if(dcmp(b[i].y-Q.y)>0)Q=b[i];
		if(i!=1)f[++cnt]=b[i]-b[i-1];if(i==n)f[++cnt]=b[1]-b[i];
	}
	n=read();
	for(int i=1;i<=n;i++)
	{
		c[i].x=read();c[i].y=read();
		if(dcmp(c[i].y-R.y)==0&&dcmp(c[i].x-R.x)<0)R=c[i];
		if(dcmp(c[i].y-R.y)>0)R=c[i];
		if(i!=1)f[++cnt]=c[i]-c[i-1];if(i==n)f[++cnt]=c[1]-c[i];
	}
	sort(f+1,f+cnt+1,cmp);
	pot k=P+Q+R;p[++tot]=k;
	for(int i=1;i<=cnt;i++)
	{
		k=k+f[i];
		if(i!=cnt&&dcmp(f[i].x*f[i+1].y-f[i].y*f[i+1].x)==0)continue;
		p[++tot]=k;
	}
	tot--;k=p[1];

應用:
1.判斷兩個凸包是否相交
兩個凸包相交的條件:存在a=b,a屬於A,b屬於B。
也就是存在a-b=0
對B取反后和A計算一下閔可夫斯基和,若包含點(0,0)則說明原方程優借,即兩個凸包有交。

2.給出三個凸包,每次詢問一個點,問能否從三個凸包中各選出一個點並連接成三角形,使得三角形的重心在詢問點上。
解:
考慮重心的表達式。設三角形的三個頂點的坐標分別為(x1,y1),(x2,y2),(x3,y3),那么重心一定位於((x1+x2+x3)/3,(y1+y2+y3)/3)。
發現這個表達式顯然是一個閔可夫斯基和的形式,因此,直接求出三個凸包的閔可夫斯基和然后按比例縮小一下即可。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM