閔可夫斯基和,是兩個歐幾里得空間的點集的和,以德國數學家閔可夫斯基命名。
點集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)。
發現這個表達式顯然是一個閔可夫斯基和的形式,因此,直接求出三個凸包的閔可夫斯基和然后按比例縮小一下即可。