1. 程式人生 > >凸包--Graham掃描法

凸包--Graham掃描法

一直聽大佬們說:凸包、凸包、凸包
一直不會。。。。。
然後。。。。
今天考試,考了一道計算幾何的簡單題。。。。
這,,,還是學一下吧。。
然後考試現場學習一下凸包演算法。

先理解一下凸包是啥東西。

這裡寫圖片描述

看看這張圖
解釋一下凸包是什麼
如果你有一堆點(原諒我畫的很凌亂)
那麼,找到一個點集
依次連線這些點
使他們形成一個凸多邊形
並且所有的點都包括在這個多邊形的內部或者邊上
這個多邊形就是一個凸包(我寫的肯定一點也不嚴謹)

不管怎麼樣,就先這樣理解一下吧。。。。。。

凸包是啥應該不難理解,那麼,給你一堆點,怎麼求凸包?

這種東西。。。。。
先大概說一下把。。。

首先找到最靠近左下的那個點,這個點一定在凸包上(不難理解吧。。。畫個圖就知道了)

以這個點為極點,其他點按照極角排序

然後按照順序依次訪問所有點,判斷可行性

這樣子幹說真是虛無縹緲的東西。。。。。。
畫圖來解釋

這裡寫圖片描述

這是一片點。

這裡寫圖片描述

找到最靠近左下的一個點

這裡寫圖片描述

其他的點按照極角排序

這裡寫圖片描述

然後把1丟到凸包的棧裡面,準備開始掃描

這裡寫圖片描述

檢查2號點是否在1的一側,(檢查一下是不是凸多邊形)
這裡檢查到2號可行,先加入到棧中

這裡寫圖片描述

檢查到3更加靠近外側(如果加入3號就會形成凹多邊形,顯然3在凸包中,而2不在)
然後把2號點彈出棧,判斷1號和3號節點的關係(同判斷2號)

這裡寫圖片描述

依次這麼判斷,最後所有凸包上的點都會在棧中

這裡寫圖片描述

這樣子演算法的步驟很顯然了。
繼續解決一些細節上的問題(貌似就一個把。。。。)
怎麼計算一個節點是否在前一個點的一側。。。。
(我說的好不專業。。。我自己都不知道該怎麼說一些名詞。。。就將就著理解一下吧。。。)

我們先拿幾個點出來

這裡寫圖片描述

其中1,2,3是當前在凸包的棧中的點,4號節點是需要判斷的點
那麼,我們需要從棧中拿最上方的兩個點(2和3節點)
把他們連線起來,再把2和4連線起來(怎麼連線?我是不會說直接用向量的座標表示就可以了)
計算一下兩個向量的叉積。。
哈,叉積。。。
解釋一下吧。。
假設2到3的向量是a(x1,y1)
2到4的向量是b(x2,y2)
那麼,計算一下它們的叉積,也就是x1y2-x2y1
換種方法來表示就是。
|a|·|b|·sin<a,b>
(所以說叉積也可以用來求出三角形的面積~這個以後還會用到的)
如果,這兩個向量的叉積≥0 證明這兩個向量平行或者夾角是個銳角
也就證明了3號節點此時一定不再凸包上(因為連線2和4之後3在凸包內側了)
把3號節點彈出棧,繼續重複上面的步驟即可。

感覺我說的有點小複雜誒。。。。
這個東東多畫點圖就會理解的

如果還是不太清楚,可以看一看程式碼。

struct Node
{
       int x,y;
}p[MAX],S[MAX];//p儲存節點的位置,S是凸包的棧 
inline bool cmp(Node a,Node b)//比較函式,對點的極角進行排序 
{
       double A=atan2((a.y-p[1].y),(a.x-p[1].x));
       double B=atan2((b.y-p[1].y),(b.x-p[1].x));
       if(A!=B)return A<B;
       else    return a.x<b.x; //這裡注意一下,如果極角相同,優先放x座標更小的點 
}
long long Cross(Node a,Node b,Node c)//計算叉積 
{
       return 1LL*(b.x-a.x)*(c.y-a.y)-1LL*(b.y-a.y)*(c.x-a.x);
}
void Get()//求出凸包 
{
       p[0]=(Node){INF,INF};int k;
       for(int i=1;i<=n;++i)//找到最靠近左下的點 
              if(p[0].y>p[i].y||(p[0].y==p[i].y&&p[i].x<p[0].x))
               {p[0]=p[i];k=i;}
       swap(p[k],p[1]);   
       sort(&p[2],&p[n+1],cmp);//對於剩餘點按照極角進行排序 
       S[0]=p[1],S[1]=p[2];top=1;//提前在棧中放入節點 
       for(int i=3;i<=n;)//列舉其他節點 
       {
              if(top&&Cross(S[top-1],p[i],S[top])>=0)
                        top--;//如果當前棧頂不是凸包上的節點則彈出 
              else  S[++top]=p[i++];//加入凸包的棧中 
       }
       //底下這個玩意用來輸出凸包上點的座標 
       //for(int i=0;i<=top;++i)
       //    printf("(%d,%d)\n",S[i].x,S[i].y);
}

接下來找一道簡單點的例題
HDU 1392

這道題目就是求出凸包然後計算周長,很簡單的題目,去試試吧。。

相關推薦

計算幾何之----Graham掃描

計算幾何之凸包(convexHull)----Graham掃描法 關於凸包的嚴格定義,這裡不打算寫出來,大家可以自行Google或者百度,因為嚴格的數學定義反而不太好理解,用最通俗的話來解釋凸包:給定

--Graham掃描

一直聽大佬們說:凸包、凸包、凸包 一直不會。。。。。 然後。。。。 今天考試,考了一道計算幾何的簡單題。。。。 這,,,還是學一下吧。。 然後考試現場學習一下凸包演算法。 先理解一下凸包是啥東西。 看看這張圖 解釋一下凸包是什麼 如果你有一堆點(原諒我畫的很凌亂) 那麼,找到一個點集 依次連線這些點 使他們

關於——Graham掃描

首先是凸包的第一種解法,graham掃描法。演算法的步驟如下: 1 首先我們要找到凸包的一個頂點,這個頂點的y座標要最小,相同的y的情況下,選擇更靠左的點 2 對給出的頂點集進行排序,按照極角遞增的順序進行排序?如何進行操作呢,我們可以用我們向量積的性質,如果向量積為正,b

Graham掃描->HDU3847

Graham掃描法求凸包 凸包定義: 點集Q的凸包(convex hull)是指一個最小凸多邊形,滿足Q中的點或者在多邊形邊上或者在其內。 凸包最常用的凸包演算法是Graham掃描法和Jarvis步進法。 Graham掃描法: 首先

二維求 graham掃描

graham掃描法求凸包的做法就是,選擇一個座標最靠近左下的點,然後作為原點,其他點按極座標排序,角度由小到大,角度想等r小的優先,然後將前兩個點放到棧中進行初始化,之後順序對每一個點進行判斷,只有該點向左發生了偏轉才將該點入棧,否則刪掉當前棧頂元素,再次判斷,直到發生了向

1015 - 計算幾何之Graham掃描 - Cows(POJ 3348)

傳送門   題意 給你一堆點,求這些點的凸包,並求出面積   分析 很久之前就做過的一道題了,還記得那是凱爺(凱爺好厲害好厲害的)講的,是Jarris步進法:按照橫縱座標對所有的點進行排序(橫座標優先) 然後就是和Graham類似的方法了,邊掃描邊

演算法(Graham掃描

目錄 一、概念 二、演算法步驟 三、程式碼實現 轉自:https://www.cnblogs.com/aiguona/p/7232243.html 一、概念 凸包(Convex Hull)是一個計算幾何(圖形學)中的概念。 在一個實數向量空間V中,對於給定集合X,所有

最小演算法(Convex Hull)(1)-Graham掃描 -計算幾何-演算法導論

基本問題: 平面上有n個點p1,p2, ..., pn, 要求求出一個面積最小的凸多邊形,使得這個多邊形包含所有平面上的點。 根據演算法導論上提供的兩個方法做一些介紹: 演算法1: Graham掃描法 下面直接給出一段虛擬碼,方便描述: GRAHAM-SCAN(Q) {

尋找Graham掃描

題意描述: 對任意給定的平面上的點集,求最小凸多邊形使得點集中的點要麼在凸多邊形的邊上,要麼在凸多邊形的內部。 Graham演算法描述: 在所有的點中找到一點p0,使得p0的縱座標值最小,在有多個最小縱座標的情況下,找橫座標最小的那一個。 將所有的點

模板(分治 or Graham掃描

問題概述:空間上有很多點,現在要用一個凸多邊形將所有點全部包住,求哪些點在這個凸多邊形上 輸入樣例:                                             對應輸出:

淺談Graham掃描

    凸包是計算幾何中的一個基本概念。在競賽中,很少單獨考察凸包,但求凸包是很多題目求解的一個關鍵性步驟。     1)凸包的性質         給定一個點集,凸包是能夠包圍所有點的最小凸多邊形。”凸包邊上的點,稱為凸包點,其餘點稱為凸包內點“(引自何援軍著《幾何計算

演算法詳解-Graham掃描

#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> using namespace std; struct nod

(Convex Hull)構造演算法——Graham掃描

凸包(Convex Hull) 在圖形學中,凸包是一個非常重要的概念。簡明的說,在平面中給出N個點,找出一個由其中某些點作為頂點組成的凸多邊形,恰好能圍住所有的N個點。 這十分像是在一塊木板上釘了N個釘子,然後用一根繃緊的橡皮筋它們都圈起來,這根橡皮筋的形狀就是所謂的凸包。 計算凸包的一個著名演

-Andrew演算法&&Graham掃描

凸包簡介: 在二維平面上(二維凸包)給出若干個點,能夠包含這若干個點的面積最小的凸多邊形稱為凸包(可以想像有很多個釘子釘在牆上,然後用一個橡皮圈套在所有的釘子上,最後橡皮圈形成的就是一個凸包)。 Graham掃描法: Graham掃描法是一種基於極角排序的進行求解的

計算幾何 : 學習筆記 --- Graham 掃描

 凸包 (只針對二維平面內的凸包) 一、定義 簡單的說,在一個二維平面內有n個點的集合S,現在要你選擇一個點集C,C中的點構成一個凸多邊形G,使得S集合的所有點要麼在G內,要麼在G上,並且保證這個凸多邊

matlab練習程式(尋找Graham掃描

  我不太清楚這個凸包在影象處理中到底會怎樣的運用,因為這個好像更多的是計算幾何或是圖形學裡面的東西。不過作為一個演算法,我感覺還是有必要研究一下的。我主要的參考資料是《演算法導論》的33.3和這個部落格。   程式碼在這裡,我只寫了主要過程,過分細節的判斷就省略了。這裡是逆時針尋找: main.m c

問題—Graham掃描

#include<iostream> #include<cmath> #include<algorithm> using namespace std; struct point { long long x; long l

HDU 5928 DP graham

clu efi cas long long gin for struct 過程 當前 給出點集,和不大於L長的繩子,問能包裹住的最多點數。 考慮每個點都作為左下角的起點跑一遍極角序求凸包,求的過程中用DP記錄當前以j為當前末端為結束的的最小長度,其中一維作為背包的是凸包內

C++ 生成算

入棧 for each odi box less swap iterator dev 數字 由於我的極差記憶力,我打算把這個破玩意先記下來。因為以後會有改動(Delaunay三角網生成算法),我不想把一個好的東西改壞了。。。 好吧…… 凸包生成算法,: 1.先在指定的寬(w

+旋轉卡殼

凸包+旋轉卡殼法 題目:poj2187 尋找最遠點對距離 #include<bits/stdc++.h> using namespace std; int n; double eps=1e-10; double add(double a,double b){//考慮精度的求和