#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
using namespace std;
struct Point
{
int x,y;
friend std::ostream &operator << (std::ostream &output,const Point &p);
friend std::istream &operator >> (std::istream &input,Point &p);
};
bool operator == (Point a,Point b)
{
return (a.x == b.x && a.y == b.y);
}
std::ostream &operator << (std::ostream &output,const Point &p)
{
output<<"( "<<p.x<<" , "<<p.y<<" ) ";
return output;
}
std::istream &operator >> (std::istream &input,Point &p)
{
input>>p.x>>p.y;;
return input;
}
template<class T>
class Link
{
private:
T data;
Link<T> *next;
Link<T> *previous;
public:
Link(T data);
void displayLink();
T getData();
void setData(T data);
Link<T> *getNext();
void setNext(Link<T> *next);
Link<T> *getPrevious();
void setPrevious(Link<T> *previous);
template<class U> friend std::ostream& operator<< (std::ostream& print, Link<U>& obj);
};
template<class T>
Link<T>::Link(T data)
{
setData(data);
setNext(NULL);
setPrevious(NULL);
}
template<class T>
void Link<T>::displayLink()
{
std::cout<<getData()<<" ";
}
template<class T>
T Link<T>::getData()
{
return data;
}
template<class T>
void Link<T>::setData(T data)
{
this->data = data;
}
template<class T>
Link<T> *Link<T>::getNext()
{
return next;
}
template<class T>
void Link<T>::setNext(Link<T> *next)
{
this->next = next;
}
template<class T>
Link<T> *Link<T>::getPrevious()
{
return previous;
}
template<class T>
void Link<T>::setPrevious(Link<T> *previous)
{
this->previous = previous;
}
template <class U>
std::ostream& operator<<(std::ostream& print, Link<U> & L)
{
print << L.getData();
return print;
}
template<class T>
class DoublyLinkedList
{
private:
Link<T> *first;
Link<T> *last;
public:
DoublyLinkedList();
~DoublyLinkedList();
Link<T> *getFirst();
void setFirst(Link<T> *first);
Link<T> *getLast();
void setLast(Link<T> *first);
bool isEmpty();
Link<T> *find(T key);
void insertFirst(T dd);
void insertLast(T dd);
void deleteFirst();
void deleteLast();
bool insertAfter(T key,T dd);
void deleteKey(T key);
void displayForward();
void displayBackward();
};
template<class T>
DoublyLinkedList<T>::DoublyLinkedList()
{
setFirst(NULL);
setLast(NULL);
}
template<class T>
DoublyLinkedList<T>::~DoublyLinkedList()
{
while(!isEmpty())
{
deleteFirst();
}
}
template<class T>
Link<T> *DoublyLinkedList<T>::getFirst()
{
return first;
}
template<class T>
void DoublyLinkedList<T>::setFirst(Link<T> *first)
{
this->first = first;
}
template<class T>
Link<T> *DoublyLinkedList<T>::getLast()
{
return last;
}
template<class T>
void DoublyLinkedList<T>::setLast(Link<T> *last)
{
this->last = last;
}
template<class T>
bool DoublyLinkedList<T>::isEmpty()
{
return getFirst()==NULL;
}
template<class T>
Link<T> *DoublyLinkedList<T>::find(T key)
{
Link<T> *current = getFirst();
while(current != NULL && !(current->getData == key))
current = current->getNext();
return current;
}
template<class T>
void DoublyLinkedList<T>::insertFirst(T dd)
{
Link<T> *newLink = new Link<T>(dd);
if(isEmpty())
setLast(newLink);
else
getFirst()->setPrevious(newLink);
newLink->setNext(getFirst());
setFirst(newLink);
}
template<class T>
void DoublyLinkedList<T>::insertLast(T dd)
{
Link<T> *newLink = new Link<T>(dd);
if(isEmpty())
{
setFirst(newLink);
}
else
{
getLast()->setNext(newLink);
newLink->setPrevious(getLast());
}
setLast(newLink);
}
template<class T>
void DoublyLinkedList<T>::deleteFirst()
{
if(isEmpty())
return;
Link<T> *temp = getFirst();
if(getFirst()->getNext() == NULL)
setLast(NULL);
else
getFirst()->getNext()->setPrevious(NULL);
setFirst(getFirst()->getNext());
delete temp;
}
template<class T>
void DoublyLinkedList<T>::deleteLast()
{
if(isEmpty())
return;
Link<T> *temp = getLast();
if(getFirst()->getNext() == NULL)
setFirst(NULL);
else
getLast()->getPrevious()->setNext(NULL);
setLast(getLast()->getPrevious());
delete temp;
}
template<class T>
bool DoublyLinkedList<T>::insertAfter(T key,T dd)
{
Link<T> *current = find(key);
if(current == NULL)
return false;
Link<T> *newLink = new Link<T>(dd);
if(current->getNext() == NULL)
{
newLink->setNext(NULL);
setLast(newLink);
}
else
{
newLink->setNext(current->getNext());
current->getNext()->setPrevious(newLink);
}
newLink->setPrevious(current);
current->setNext(newLink);
return true;
}
template<class T>
void DoublyLinkedList<T>::deleteKey(T key)
{
Link<T> *current = find(key);
if(current==NULL)
return;
if(current->getPrevious() == NULL)
setFirst(current->getNext());
else
current->getPrevious()->setNext(current->getNext());
if(current->getNext() == NULL)
setLast(current->getPrevious());
else
current->getNext()->setPrevious(current->getPrevious());
delete current;
}
template<class T>
void DoublyLinkedList<T>::displayForward()
{
std::cout<<"List (first-->last): ";
Link<T> *current = getFirst();
while(current != NULL)
{
current->displayLink();
current = current->getNext();
}
std::cout<<"\n";
}
template<class T>
void DoublyLinkedList<T>::displayBackward()
{
std::cout<<"List (last-->first): ";
Link<T> *current = getLast();
while(current != NULL)
{
current->displayLink();
current = current->getPrevious();
}
std::cout<<"\n";
}
int ScaledDistance(Point u,Point v,Point p)
{
return (p.x - v.x) * (u.y - v.y) - (p.y - v.y) * (u.x - v.x);
}
int Direction(Point u,Point v, Point p)
{
return (p.x - v.x) * (u.y - v.y) - (p.y - v.y) * (u.x - v.x);
}
int Projection(Point u,Point v,Point p)
{
return (p.x - v.x) * (u.x - v.x) + (p.y - v.y) *(u.y - v.y);
}
void Select(Point &p,Point &q, DoublyLinkedList<Point> S)
{
Point pt;
Link<Point> *element = S.getFirst();
q = element->getData();
p = q;
element = element->getNext();
while(element != NULL)
{
pt = element->getData();
if((pt.y < q.y) || (pt.y == q.y && pt.x < q.x)) q = pt;
if((pt.y > p.y) || (pt.y == p.y && pt.x > p.x)) p = pt;
element = element->getNext();
}
}
void Split(Point p, Point q, DoublyLinkedList<Point> &S, DoublyLinkedList<Point> &R, DoublyLinkedList<Point> &L)
{
int dir;
Point pt;
while(!S.isEmpty())
{
pt = S.getFirst()->getData();
S.deleteFirst();
dir = Direction(p,q,pt);
if(dir > 0) R.insertLast(pt);
if(dir < 0) L.insertLast(pt);
}
}
void PruneAndSplit(Point p, Point q,Point r, DoublyLinkedList<Point> &S, DoublyLinkedList<Point> &U, DoublyLinkedList<Point> &L)
{
DoublyLinkedList<Point> internal1,internal2;
Split(p,r,S,U,internal1);
Split(r,q,internal1,L,internal2);
while(!internal2.isEmpty())
internal2.deleteFirst();
}
Point FarthestPoint(Point p,Point q,DoublyLinkedList<Point> S)
{
int maxdist,dist;
Point r,pt;
maxdist = 0;
Link<Point> *element = S.getFirst();
while(element != NULL)
{
pt = element->getData();
dist = ScaledDistance(p,q,pt);
if(dist > maxdist)
{
maxdist = dist;
r = pt;
}
else if(dist == maxdist)
{
if(Projection(p,q,pt) > Projection(p,q,r))
{
maxdist = dist;
r = pt;
}
}
element = element->getNext();
}
return r;
}
void QuickHull(Point p,Point q,DoublyLinkedList<Point> &S,DoublyLinkedList<Point> &CH)
{
Point r;
DoublyLinkedList<Point> U,L;
if(!S.isEmpty())
{
r = FarthestPoint(p,q,S);
PruneAndSplit(p,q,r,S,U,L);
QuickHull(p,r,U,CH);
CH.insertLast(r);
QuickHull(r,q,L,CH);
}
}
void Solve(DoublyLinkedList<Point> &A,DoublyLinkedList<Point> &CH)
{
DoublyLinkedList<Point> S,L,R;
Point p,q;
Link<Point> *element = A.getFirst();
while(element != NULL)
{
S.insertLast(element->getData());
element = element->getNext();
}
Select(p,q,S);
Split(p,q,S,R,L);
CH.insertLast(p);
QuickHull(p,q,R,CH);
CH.insertLast(q);
QuickHull(q,p,L,CH);
}
int main(int argc, char *argv[])
{
DoublyLinkedList<Point> A;
DoublyLinkedList<Point> B;
stringstream ss;
Point p;
string line;
int counter;
while(getline(cin,line))
{
ss.clear();
ss.str(line);
counter = 1;
while(ss)
{
try
{
switch(counter)
{
case 1:
{
ss>>p.x;
break;
}
case 0:
{
ss>>p.y;
A.insertLast(p);
break;
}
}
}
catch(...)
{
}
counter = (counter + 1)%2;
}
Solve(A,B);
cout<<"List A \n";
A.displayForward();
A.displayBackward();
cout<<"List B \n";
B.displayForward();
B.displayBackward();
while(!A.isEmpty())
A.deleteFirst();
while(!B.isEmpty())
B.deleteFirst();
}
return EXIT_SUCCESS;
}