←  Геометрия

олимпиадники-информатики

»

Выпуклая оболочка Грехэма (сортировка по к...

LVP фотография LVP 24 окт 2020

Код от Кузьмичева Алексея, нахождения выпуклой оболочки по Алгоритму Грехема , используя сортировку точек по Углу через косое произведение векторов (решение задачи Informatics/mccme.ru 1877)

#include <bits/stdc++.h>
 
using namespace std;
 
struct point /// структура обозначающая точку в нашей системе координат
{
	int x, y;
};
 
point fst; /// 1 - я точка
 
long long dist_sq(int x1 , int y1 , int x2 , int y2) { /// функция, которая возвращает квадрат расстояние от 1-й точки до другой
	long long X1 = x1 , X2 = x2 , Y1 = y1 , Y2 = y2;
	return ((X1 - X2) * (X1 - X2) + (Y1 - Y2) * (Y1 - Y2));
}
 
long long cross (point a1, point a2, point b1, point b2) /// функция, которая возвращает косое произведение векторов
{
return 1ll * (a2.x - a1.x) * (b2.y - b1.y) - 1ll * (b2.x - b1.x) * (a2.y - a1.y);
}
 
bool comporator(point l , point r) { /// компоратор для сравнения значений косого произведения в sort
	if (cross(l , fst , fst , r) < 0) {
    	return 1;
	}
	if (cross(l , fst , fst , r) == 0 && dist_sq(fst.x , fst.y , l.x , l.y) < dist_sq(fst.x , fst.y , r.x , r.y)) {
    	return 1;
	}
	return 0;
}
 
int main() {
	int n;
	cin >> n;
	point a[n];
	for (int i = 0; i < n; i++) { /// считывание + нахождение самой левой точки из самых нижних
    	cin >> a[i].x >> a[i].y;
    	if (a[0].y > a[i].y) {
        	swap(a[0] , a[i]);
    	} else {
        	if (a[0].y == a[i].y && a[i].x < a[0].x) {
            	swap(a[0] , a[i]);
        	}
    	}
	}
	fst = a[0]; /// самая первая точка
	sort(a + 1 , a + n , comporator); /// сортировка(от второй точки)
	deque <point> st; /// стек для построения оболочки
	st.push_back(a[0]);
for (int i = 1; i < n; i++) /// проход по алгоритму построения
{
  while (st.size() > 1 && cross(st[st.size() - 2] , st[st.size() - 1] , st[st.size() - 1] , a[i]) <= 0)
  {
        	st.pop_back();
  }
        	if (st.back().x != a[i].x || st.back().y != a[i].y) st.push_back(a[i]);
  }
 
	if (n % 2 != 0) { /// т.к. в 1877 если n нечетно нужно вывести оболочку по часовой стрелке, то развернём стек
    	reverse(st.begin() , st.end());
	}
 
	cout << st.size() << endl;
	for (auto to : st) { /// вывод оболочки
    	cout << to.x << " " << to.y << endl;
	}
	return 0;
}
Ответить