題意:找出凸包,然後逆時針輸出,測試數據中沒有相鄰的邊是共線的。
注意:雖然兩相鄰邊不會共線,但是如果圖形是”山型“,想象三座山一樣高,排在一起的形狀,那麼三個山峯只能留下旁邊的兩個點,中間的點不能出現在凸包中。這也是一個WA點。相應的處理就是,將叉積 <= 0 改爲 < 0;
代碼:
//uva 681 Convex Hull Finding
//AC By Warteac
//Runtime:0.155s
//2013-5-17
/*
模板一:不包括邊上的點
題目限制:沒有相鄰的兩個邊是共線的,所以可以用這個模板
WA:d <= 0 改爲 d < 0 就ac,從下面的測試數據可以看到差別
1
8
-3 0
-1 4
0 3
1 4
2 3
3 4
4 0
-3 0
-1
*/
#include<iostream>
#include<cstdio>
#include<vector>
#include<stack>
#include <iomanip>
#include<algorithm>
#include<cmath>
using namespace std;
typedef int PType;//定義點的類型
typedef double CType;//定義重心點的類型
///////////////////////////////////////
struct Point{
PType x,y;
Point(PType a = 0, PType b = 0){x = a; y = b;}
void print(){cout << x << " " << y << endl;}
Point operator -(Point p){return Point(x - p.x, y - p.y);}
}pBase;//最左下的點
typedef Point Vector;//向量
int direction(Vector v1,Vector v2){//求兩個向量的叉積
return (v1.x*v2.y-v1.y*v2.x);
}
bool cmp(Point p1, Point p2){//比較函數
int d = direction(p1 - pBase, p2 - pBase);
if(d == 0){//極角相同
return abs(p1.x) < abs(p2.x);//距原點的距離從小到大排
}else {
return d < 0;//按逆時針排序
}
}
bool grham_scan(vector <Point> p , vector <Point> &parray){//求凸包的算法
//find first point p0 with minimum y-coordinate or minimun x-coordinate if y are the same
int index = 0;
for(int i = 1; i < p.size(); i++){
if(p[i].y < p[index].y ||(p[i].y == p[index].y && p[i].x < p[index].x))
index = i;
}
swap(p[0],p[index]);
pBase = p[0];
sort(p.begin()+1,p.end(),cmp);
//get the convex hull from p
parray.clear();
parray.push_back(p[0]);
parray.push_back(p[1]);
p.push_back(p[0]);
for(int i = 2; i < p.size(); i++){
Vector v1 (p[i].x - parray.back().x, p[i].y - parray.back().y);
Vector v2 (parray.back().x - (parray.end()-2)->x, parray.back().y - (parray.end()-2)->y);
int d = direction(v2,v1);
if(d < 0) {parray.push_back(p[i]);} //Modify ;“ <= 、 < 傻傻分不清楚”
else{
parray.pop_back();i--;
}
}
return true;
}
//////////////////////////////////////////////////////
int main(){
int caseNum,num;
vector <Point> temp;
vector <Point> v;
Point t;
cin >> caseNum;
cout << caseNum << endl;
for(int x = 0; x < caseNum; x++){
cin >> num;
temp.clear();//clear once input
while(num--){
cin >> t.x >> t.y;
temp.push_back(t);
}
temp.pop_back();
if(grham_scan(temp,v)== true){
cout << v.size() << endl;
for(int i = v.size()-1; i >= 0; i--){
v[i].print();
}
}else{
cout << "0" <<endl;
}
if(x < caseNum-1) {
cout << "-1" << endl;
cin >> num;//input -1
}
}
return 0;
}
/*
Sample Input
3
15
30 30
50 60
60 20
70 45
86 39
112 60
200 113
250 50
300 200
130 240
76 150
47 76
36 40
33 35
30 30
-1
12
50 60
60 20
70 45
100 70
125 90
200 113
250 140
180 170
105 140
79 140
60 85
50 60
-1
6
60 20
250 140
180 170
79 140
50 60
60 20
Sample Output
3
8
60 20
250 50
300 200
130 240
76 150
47 76
30 30
60 20
-1
6
60 20
250 140
180 170
79 140
50 60
60 20
-1
6
60 20
250 140
180 170
79 140
50 60
60 20
*/