Graham算法笔记

一切参照题解
笔记部分:
怎么判断旋转方向:
image
如图,第一次入栈,P2直接进入

image
此处为什么p3是左转:
我们判断左转还是右转的方法:
看要进入的点pi与栈顶的点pa和栈第二个点pb:
此处就是看向量p1p2到向量p1p3是顺时针还是逆时针,如果是逆时针,为左转,顺时针为右转
此处是逆时针

然后我们看接下来:
image
p4将要入栈时候,栈顶是p3,下面一个是p2,那么我们就以p2为起点,看向量p2p3到向量p2p4是顺时针还是逆时针,此处我们发现是顺时针,就是右转。

如何判断两个向量是顺时针还是逆时针?
做向量a叉乘b = xayb - xbya > 0 :逆时针,<0顺时针。
// AC代码:题目传送门
image

#define _CRT_SECURE_NO_WARNINGS 1

#include <iostream>
#include <stack>
#include <algorithm>
#include <cmath>

using namespace std;

// 方法:Graham算法

int n;
const int MAXN = 1e5 + 5;


struct Point
{
	double x, y;
}p[MAXN],s[MAXN];

//// 判断左转右转
//bool check(Point p1, Point p2, Point p)
//{
//	// p 为起始点,p1 p2分别为终点,判断向量pp1到pp2是顺时针还是逆时针
//	int x1 = p1.x - p.x,
//		y1 = p1.y - p.y,
//		x2 = p2.x - p.x,
//		y2 = p2.y - p.y;
//	if (x1 * y2 - x2 * y1 > 0)  // 逆时针
//		return true;  // 左转
//	return false;
//}

double check(Point a1, Point a2, Point b1, Point b2)//检查叉积是否大于0,如果是a就逆时针转到b 
{
	return (a2.x - a1.x) * (b2.y - b1.y) - (b2.x - b1.x) * (a2.y - a1.y);
}
double d(Point a, Point b)  // 距离公式
{
	return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
}

bool cmp(Point p1, Point p2)//排序函数, sort时候,是调用 a < b 判断是否成立调用的是cmp,即cmp(a,b) 如果true, a在b前,否则,b在a前
{
	double tmp = check(p[1], p1, p[1], p2);
	if (tmp > 0)
		return 1;
	if (tmp == 0 && d(p[0], p1) < d(p[0], p2))  // 二者平行
		return 1;
	return 0;
}
int main()
{
	double mid;
	scanf("%d", &n);
	for (int i = 1; i <= n; i++)
	{
		cin >> p[i].x >> p[i].y;
		if (i != 1 && p[i].y < p[1].y)// 找出最低点p[1]
		{
			/*mid = p[1].y; p[1].y = p[i].y; p[i].y = mid;
			mid = p[1].x; p[1].x = p[i].x; p[i].x = mid;*/
			swap(p[i], p[1]);
		}
		if (i != 1 && p[i].y == p[1].y && p[i].x < p[1].x)
		{
			swap(p[i], p[1]);
		}
	}
	sort(p+2, p+ 1 + n,cmp);
	s[1] = p[1];
	int cnt = 1;
	for (int i = 2; i <= n; i++)
	{
		while (cnt > 1 && check(s[cnt - 1], s[cnt], s[cnt], p[i]) <= 0)
			--cnt;
		s[++cnt] = p[i];
	}
	s[++cnt] = p[1];  // 第一个点同时也是末尾
	double sum_d = 0;
	
	for (int i = 1; i < cnt; i++)
		sum_d += d(s[i], s[i + 1]);
	printf("%.2lf\n", sum_d);
	return 0;
}
posted @ 2023-01-18 20:53  诗子黎  阅读(31)  评论(0编辑  收藏  举报