凸包问题及凸包的可视化

凸包

  • 凸包: 一个点集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

运行结果:
在这里插入图片描述

发布了59 篇原创文章 · 获赞 47 · 访问量 5493

猜你喜欢

转载自blog.csdn.net/qq_44755403/article/details/104524825