题目给出一个多边形,要求出这个多边形的凸包;
在一个点集D中,按一定顺序选取子集Q
使得Q中所有点顺次连接所构成的封闭凸多边形包住D中所有点
可以形象地理解为:有许多个钉子钉在平面上,用一根牛皮筋把所有点包住
找出凸包的思路是:
先把题目给出的多边形的点集合按x坐标从小到大排序,x相同的按y从小到大排序;(点的<前面已经重载过,符合这个要求)
将排序后的集合遍历,先把2个放入栈u中,如果新加入一个点后,能保证u中的点仍然是凸包的,就加进去,否则就pop出来一个点,直到u成为一个凸包为止;这样就得到了凸包的上半部分;
再把点按照x从大到小排序,x相同的y从大到小排序;
其他的操作同上,由此得到凸包的下半部分。
最后,把上下两部分合并(按照要求,本题是要求逆时针方向输出生成凸包中的点)
凸包的得到过程如下:
Polygon scan(Polygon S){
sort(S.begin(),S.end());
Polygon u,t;
if (S.size() < 3) return S;
int len=S.size();
u.push_back(S[0]);
u.push_back(S[1]);
t.push_back(S[S.size()-1]);
t.push_back(S[S.size()-2]);
for(int i=2;i<len;i++){
for(int j=u.size();j>=2&&(ccw(u[j-2], u[j-1], S[i])==COUNTER_CLOCKWISE);j--){
u.pop_back();
}
u.push_back(S[i]);
}
for(int i=len-3;i>=0;i--){
for(int j=t.size();j>=2&&(ccw(t[j-2],t[j-1],S[i])==COUNTER_CLOCKWISE);j--){
t.pop_back();
}
t.push_back(S[i]);
}
reverse(t.begin(), t.end());
for (int i = u.size() - 2; i >= 1; i--)
t.push_back(u[i]);
return t;
}
构建完成凸包后,按照题目要求输出即可
题目代码如下:
int cmp(Point A, Point B) //竖直排序
{
return (A.y<B.y || (A.y == B.y&&A.x<B.x));
}
int main (){
Polygon g, ans ,temp;
Point t;
int n, len;
scanf("%d", &n);
for (int i = 0; i < n; i++) {
scanf("%lf %lf", &t.x, &t.y);
g.push_back(t);
}
ans = scan(g);
temp = ans;
// 选出最左侧最下端的点开始输出
sort(temp.begin(), temp.end(),cmp);
int index;
for (int i = 0; i < ans.size(); i++)
if (ans[i] == temp[0])
index = i;
cout<<ans.size()<<endl;
for (int i = 0; i < ans.size(); i++)
printf("%d %d\n", int(ans[(i + index) % ans.size()].x),
int(ans[(i + index) % ans.size()].y));
return 0;
}
错点:
1.输出的时候以凸多边形最下端最左侧的顶点为起点,按逆时针方向依次输出坐标;