uva 681 Convex Hull Finding

题意:找出凸包,然后逆时针输出,测试数据中没有相邻的边是共线的。

注意:虽然两相邻边不会共线,但是如果图形是”山型“,想象三座山一样高,排在一起的形状,那么三个山峰只能留下旁边的两个点,中间的点不能出现在凸包中。这也是一个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
*/


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值