1. 程式人生 > >凸包模板(分治 or Graham掃描法)

凸包模板(分治 or Graham掃描法)

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

輸入樣例:                                             對應輸出:

4                                                             0 0

0 0                                                          2 3

1 1                                                          3 0

2 3

3 0

分治法(時間複雜度nlogn):

原理:將一個大問題分成幾個結構相同的子問題,再把子問題再分成幾個更小的子問題…….然後我們就能用遞迴的

方法,分別求這些子問題的解,最後把每個子問題的解"組裝"成原來大問題的解

步驟:

1、把所有的點都放在二維座標系裡面,那麼橫座標最小和最大的兩個點P1和Pn一定是凸包上的點,這樣點集就被分

成了兩部分,即X軸的上面和下面,它們分別叫做上包和下包

2、對上包求距離直線P1Pn最遠的點Pmax,對下包一樣處理

3、作直線P1Pmax、PnPmax,把直線P1Pmax左側的點當成是上包,把直線PnPmax右側的點也當成是上包,對下

包一樣處理

4、重複步驟2、3直到上方沒有點

#include<stdio.h>
#include<limits.h>
#include<string.h>
typedef struct
{
	int x;
	int y;
	int temp;		/*若這點在凸包上,則temp==1,否則temp==0*/
}Point;
Point s[105];
int n;
void Sechup(int a, int b);
void Sechdown(int a, int b);
int main(void)
{
	int T, i, a, b, ax, bx;
	scanf("%d", &T);
	while(T--)
	{
		memset(s, 0, sizeof(s));
		ax = INT_MAX;
		bx = INT_MIN;
		scanf("%d", &n);
		for(i=1;i<=n;i++)
		{
			scanf("%d%d", &s[i].x, &s[i].y);
			if(s[i].x<ax)
				ax = s[i].x, a = i;
			if(s[i].x>bx)
				bx = s[i].x, b = i;
		}
		s[a].temp = s[b].temp = 1;
		Sechup(a, b);			/*上包遞迴*/
		Sechdown(a, b);				/*下包遞迴*/
		for(i=1;i<=n;i++)
		{
			if(s[i].temp==1)
				printf("%d %d\n", s[i].x, s[i].y);
		}
	}
	return 0;
}
/*若向量叉乘為負,說明點在直線下面,否則在直線上面(參照直線方向為從左到右)*/
void Sechup(int a, int b)
{
	int i, max, c;
	max = 0;
	for(i=1;i<=n;i++)
	{
		if((s[b].x-s[a].x)*(s[i].y-s[a].y)-(s[b].y-s[a].y)*(s[i].x-s[a].x)>max)
		{
			max = (s[b].x-s[a].x)*(s[i].y-s[a].y)-(s[b].y-s[a].y)*(s[i].x-s[a].x);
			c = i;		/*用向量叉乘求三點三角形面積,使三角形面積最大的那個(非直線上的)點便是離參照直線最遠的點Pmax*/
		}
	}
	if(max!=0)/*參照直線上方有點*/
	{
		s[c].temp = 1;
		Sechup(a, c);
		Sechup(c, b);
	}
}

void Sechdown(int a, int b)
{
	int i, max, c;
	max = 0;
	for(i=1;i<=n;i++)
	{
		if((s[b].x-s[a].x)*(s[i].y-s[a].y)-(s[b].y-s[a].y)*(s[i].x-s[a].x)<max)
		{
			max = (s[b].x-s[a].x)*(s[i].y-s[a].y)-(s[b].y-s[a].y)*(s[i].x-s[a].x);
			c = i;
		}
	}
	if(max!=0)
	{
		s[c].temp = 1;
		Sechdown(a, c);
		Sechdown(c, b);
	}
}


Graham掃描法(時間複雜度nlogn):

步驟: 

1、找出y值最小(若y值同等最小,取x小的那個)的作為原點P1

2、以P1為座標原點,將所有點按相對於P0的幅角(連線原點與x軸的夾角大小)從小到大排序,若幅角相同則按與原

點的距離從小到大排序,並依次給點標記P2、P3……Pn

3、初始點P1和第二個點P2入佇列,設P3是當前點

4、設當前隊伍尾端的點A(x1, y1),隊伍尾端倒數第二個點B(x2, y2)和當前點C(x3, y3),求向量AB與向量AC的叉

乘,若為正,則說明點A不在凸包上,將點A踢出佇列,執行步驟5,否則說明點在凸包上,執行步驟6

5、當前點仍不變,繼續執行步驟4

6、當前點入隊,將下一個點作為當前點,執行步驟4,直到所有點全部遍歷完畢(最後一個點Pn入隊)

#include<stdio.h>
#include<limits.h>
#include<stdlib.h>
#include<string.h>
#include<deque>
#include<algorithm>
using namespace std;
typedef struct
{
	int x;
	int y;
}Point;
int n, temp;
Point top1, top2, s[105];
deque<Point> q;
bool comp2(Point a, Point b)	/*按幅角排序*/
{
	if((a.x-top1.x)*(b.y-top1.y)-(a.y-top1.y)*(b.x-top1.x)>0)
		return 1;
	else if((a.x-top1.x)*(b.y-top1.y)-(a.y-top1.y)*(b.x-top1.x)==0 && abs(a.x-top1.x)<abs(b.x-top1.x))
		return 1;
	return 0;
}
int main(void)
{
	int T, i, ax, ay;
	scanf("%d", &T);
	while(T--)
	{
		ax = ay = INT_MAX;
		scanf("%d", &n);
		for(i=1;i<=n;i++)
		{
			scanf("%d%d", &s[i].x, &s[i].y);
			if(s[i].y<ay || s[i].y==ay && s[i].x<ax)
				temp = i, ay = s[i].y, ax = s[i].x;		/*步驟1*/
		}
		top1 = s[temp];
		sort(s+1, s+n+1, comp2);
		q.push_back(s[1]);
		q.push_back(s[2]);
		temp = 3;		/*步驟3*/
		while(temp<=n)
		{
			top1 = q.back();
			q.pop_back();		/*臨時彈出用作判定*/
			top2 = q.back();
			if((top2.x-top1.x)*(s[temp].y-top1.y)-(top2.y-top1.y)*(s[temp].x-top1.x)<=0)		/*步驟4*/
			{
				q.push_back(top1);		/*符合條件,臨時彈出的歸隊*/
				q.push_back(s[temp]);	/*當前點入隊*/
				temp++;			/*下一個點作為當前點*/
			}
			/*不符合條件*/
		}
		while(q.empty()==0)
		{
			top1 = q.back();
			printf("%d %d\n", top1.x, top1.y);
			q.pop_back();
		}
	}
	return 0;
}


相關推薦

模板分治 or Graham掃描

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

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

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

演算法Graham掃描

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

尋找Graham掃描

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

matlab練習程式尋找Graham掃描

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

模板安德魯

重新 一個點 將不 構造 tor 方向 clas oid AC struct point { double x,y; }a[Max]; bool cmp(point a,point b) { if(a.x!=b.x) return

1015 - 計算幾何之Graham掃描 - CowsPOJ 3348

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

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

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

codevs1298, hdu1392 模板

叉積 pan 向量 math != 不能 p s ace iostream 題意: 求凸包周長。 總結: 測試模板。 代碼: #include <iostream> #include <cstdio> #include <cstring>

模板(Graham)

//凸包,Graham演算法 //點編號0~n-1 //返回凸包結果Stack[0~Top-1] Point List[maxn],Stack[maxn]; int Top; bool cmp( Poi

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

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

淺談Graham掃描

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

--Graham掃描

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

演算法詳解-Graham掃描

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

關於——Graham掃描

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

-Andrew演算法&&Graham掃描

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

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

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

Graham掃描->HDU3847

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

二維求 graham掃描

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

問題—Graham掃描

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