凸包
- 凸包: 一个点集S的凸包是包含S的最小凸集合,其中,最小是指S的凸包一定是所有包含S的凸集合的子集。 对于平面上n个点的集合S,它的凸包就是包含所有这些点(或者在内部,或者在边界上)的最小凸多边形。
例如:
- 为了解决凸包问题,需要找出凸多边形的顶点,这样的点称为极点。
- 一个凸集合的极点应该具有这样性质:对于任何以凸集合中的点为端点的线段来说,它不是这种线段中的点。
- 解决思路:
1. 在平面上,穿过两个点(x1, y1)和(x2, y2)的直线是由下面的方程定义的:
ax + by = c (其中,a=y2-y1, b=x1-x2, c=x1y2-y1x2) 。
2.想法: 这样一条直线把平面分成两个半平面:其中一个半平面中的点都满足ax + by>c,另一个半平面中的点都满足ax + by<c,因此,为了检验这些点是否位于这条直线的同一边,可以简单地把每个点代入方程ax + by = c,检验这些表达式的符号是否相同。
#include<iostream>
#include<stdlib.h>
#include<graphics.h>
#pragma comment(lib,"Winmm.lib")
using namespace std;
const int MAX = 100;
int width = 650, height = 700;//画板大小
struct Node
{
double x, y;//一个点的xy坐标
bool tag;//是否极点
};
void show()
{
initgraph(width, height);//画布
setbkcolor(WHITE);//背景色
cleardevice();//用背景色来清屏
setaspectratio(1, -1);//反转坐标轴
setorigin(width / 2, height / 2);//设置坐标轴原点
setlinecolor(BLACK);
line(-250, 0, 250, 0);
line(250, 0, 240, -10);
line(250, 0, 240, 10);
settextcolor(BLACK);
char s = 'X';
outtextxy(240, -28, s);
line(0, 300, 0, -300);
line(0, 300, 10, 290);
line(0, 300, -10, 290);
}
int main()
{
Node node[MAX];//储存点
FILE *fp;
int n;//点的个数
cin >> n;
getchar();
int r,l;//标记点是否都在线的一侧
int m = 30;//绘图放大倍数
fp = fopen("C:\\Users\\lu\\Desktop\\凸包结点.txt", "r");
for (int i = 0; i < n; i++)
{
fscanf_s(fp, "%lf%lf", &node[i].x, &node[i].y);
node[i].tag = false;//初始时都不是极点
}
fclose(fp);
int i, j, k;//循环变量
double a, b, c;
double d;
show();//调用画布
setfillcolor(BLUE);
for (int i = 0; i < n; i++)
{
fillcircle(node[i].x * m, node[i].y * m, 3);//画出点
Sleep(200);
}
for (int i = 0; i < n; i++)
{
for (int j = i + 1; j < n; j++)
{//穷举点集中任意两点组成的直线ax+by=c
a = (node[j].y) - (node[i].y);//
b = (node[i].x) - (node[j].x);
c = (node[i].x * node[j].y) - (node[i].y * node[j].x);
l = r = 0;
int k;
for (k = 0; k < n; k++)
{//穷举点集中的每一点
d = a * (node[k].x) + b * (node[k].y);
if (d > c)
l++;
else if (d <c)
r++;
if (l * r != 0) break;//直线两侧都有点,
}
if (r == 0 || l == 0)
{
node[i].tag = true;//是极点
node[j].tag = true;
setlinecolor(RED);
line(node[i].x * m, node[i].y * m, node[j].x * m, node[j].y * m);
Sleep(200);
}
}
}
if(getchar())
closegraph();
for (i = 0; i < n; i++)
{
if (node[i].tag == true)
{
cout << node[i].x << ' ' << node[i].y << endl;
}
}
return 0;
}
测试数据:
3 3
5 4
3 5
6 3
-2 -1
5 6
2 7
1 1
-4 -4
-2 -3
-6 -1
-2 -4
2 2
1 3
-2 -5
-7 -2
2 3
3 1
运行结果: