凸包算法總結:
凸包是指覆蓋平面座標系內若干點的面積最小的凸多邊形。求凸包的第一步是確定:
凸包的定點都在給定的點中。通過幾何方法反證很容易得到這一結論。所以,只要
從所有點中挑選若干正確的點,按順序(順時針或逆時針)排列,就相當與求得了凸
包。一種簡便的方法是"包裹法"(Gift-Wrapping)。將y座標最低的點作爲凸包的第
一個頂點H1(易證,所有點中x或y座標取到最大或最小值的點一定是凸包頂點之一)
找到滿足條件的點,該點與水平線的叉積爲正且夾角最小,作爲凸包的第二個頂點
H2。再求與線段H1H2叉積爲正且夾角最小的點,。。。。依此類推。
*/
//計算幾何中的凸包問題程序(graham算法)
#i nclude <stdio.h>
#i nclude <stdlib.h>
#i nclude <math.h>
#define MAXN 10000
/* 頂點的類型定義 */
typedef struct {
double x;
double y;
double arCos;
}Point1;
int n; // 頂點的個數
Point1 points[MAXN]; // 頂點數組
int stack[MAXN]; // 棧
/*主函數*/
int main()
{
void Init();
void Make();
Init(); //程序數據的讀入
Make(); //程序算法過程
while(1);
return 0;
}
/*數據讀入函數*/
void Init()
{
FILE *in; // 採用讀文件的方式,讀入數據
int i;
in = fopen("281.txt", "r");
fscanf(in, "%d", &n);
for(i = 0; i < n; ++i)
fscanf(in, "%lf%lf", &points[i].x, &points[i].y);
fclose(in); // 關閉文件
}
/*算法實現函數*/
void Make()
{
int Multi(Point1, Point1, Point1); //計算兩個向量的積
double Angle(int); //計算其餘頂點與第一頂點的角度,爲排序做準備
void QSort(int, int); //對頂點進行快速排序
void Swap(int, int);
int i, j, t;
double min = 32767.0;
for(i = 0; i < n; ++i){ //找第一個頂點,做爲算法的起始頂點
if(points[i].y < min) {
j = i;
min = points[i].y;
}
}
Swap(0, j);
for(i = 1; i < n; ++i){ //計算除第一頂點外的其餘頂點到第一點的線段與x軸的夾角
points[i].arCos = Angle(i);
}
QSort(1, n-1); //根據所得到的角度進行快速排序.
for(i = 0; i <= 2; ++i) stack[i] = i; //將前3個頂點壓棧
t = 2;
while(i < n) {
/*如果新的點,與最近入棧中的2點構成了一個"凹"角, 則將棧頂元素出棧. 直到把棧檢查完*/
while(Multi(points[stack[t-1]], points[stack[t]], points[i]) && t >= 1)
t--;
t++; // 將新點壓棧
stack[t] = i;
i++;
}
/*打印結果*/
for(i = 0; i <=t; ++i)
printf("<%.2lf, %.2lf>/n",points[stack[i]].x, points[stack[i]].y);
}
int Multi(Point1 px, Point1 py, Point1 pz)
{
double k;
k = (py.x-px.x)*(pz.y-py.y) - (pz.x-py.x)*(py.y-px.y); // 計算兩個向量的向量積,
// 判斷3個點所成的角是不是一個"凹"角.
if(k < 0) return 1;
return 0;
}
/*角度計算函數*/
double Angle(int i)
{
double j, k, m, n;
j = fabs(points[i].x - points[0].x);
k = fabs(points[i].y - points[0].y);
m = sqrt(j*j+k*k); //得到頂點i 到第一頂點的線段長度.
n = acos(j/m); //得到該線段與x軸的角度
//強悍
return n;
}
void QSort(int top, int bot)
{
//快排
int Loc(int, int);
int pos;
if(top < bot) {
pos = Loc(top, bot);
QSort(top, pos-1);
QSort(pos+1, bot);
}
}
int Loc(int top, int bot)
{
void Swap(int, int);
double x = points[top].arCos;
int j, k;
j = top+1;
k = bot;
while(1) {
while(j < bot && points[j].arCos < x) j++;
while(k > top && points[k].arCos > x) k--;
if(j >= k) break;
Swap(j, k);
}
Swap(top, k);
return k;
}
void Swap(int px, int py)
{
Point1 k;
k = points[px];
points[px] = points[py]; //注意
points[py] = k;
}