题目链接:点击这里
解题思路:
实际上是求从第一个点出发逆时针路径到达最后一个点的凸包,其实一个细节就是凸包上的点上,三点共线的中间那个点是否要删除?那就看他后面的那个点的下标是否小于它,小于的话删除之后字典序就更小了。
#include<bits/stdc++.h>
using namespace std;
const int mx = 2e5 + 10;
typedef long long ll;
int n,m,ans[mx],top,ma;
struct node
{
int x,y;
int pos;
}s[mx],tubeg[mx],w;
bool vis[mx];
ll judge(node p1,node p2,node p0)//面积公式判断正负值
{
ll ans = 1ll*(p1.x-p0.x)*(p2.y-p0.y) - 1ll*(p2.x-p0.x)*(p1.y-p0.y);
return ans;
}
bool cmp(node a,node b)
{
ll c = judge(w,b,a);//极角排序,同角度按距离从小到大排
if(b.x==a.x&&b.y==a.y) return a.pos > b.pos;
if(!c) return pow(a.x-w.x,2)+pow(a.y-w.y,2) < pow(b.x-w.x,2)+pow(b.y-w.y,2);
return c > 0;
}
void Graham()
{
tubeg[0] = s[0],tubeg[1] = s[1];
top = 2;
for(int i=2;i<n;i++)
{
while(top>1&&judge(tubeg[top-2],s[i],tubeg[top-1])<=0)
{
if(judge(tubeg[top-2],s[i],tubeg[top-1])<0||tubeg[top-1].pos>s[i].pos) top--;
else break;
}
tubeg[top++] = s[i];
}
for(int i=0;i<top;i++) printf("%d%c",tubeg[i].pos+1,i==top-1?'\n':' ');
}
int main()
{
int t;
scanf("%d",&t);
while(t--){
scanf("%d",&n);
memset(vis,0,sizeof(vis));
for(int i=0;i<n;i++){
scanf("%d%d",&s[i].x,&s[i].y);
s[i].pos = i;
}
w = s[0];
sort(s+1,s+n,cmp);
Graham();
}
return 0;
}