很好的题。。可以来检验一发graham算法求凸包是否掌握了,其实这个题没有最外侧的点与x轴,或者与y轴平行的数据,不然的话还要修改一个部分~~
可以试试这组数据
1
8
1 1 1
2 2 1
3 1 2
4 2 2
5 1 3
6 2 3
7 1 4
8 2 4
正确的答案应该输出的是8 1 2 4 6 8 7 5 3
但是输出的是8 1 2 8 7 3 4 6 5也能AC,这就是求凸包的时候判断是否有等于了~~~~~
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
const double EPS=1e-10;
const double pi=acos(-1.0);
using namespace std;
double add(double a,double b){
if(abs(a+b)<=EPS*(abs(a)*abs(b)))
return 0;
return a+b;
}
struct P
{
double x,y;
int index;
P(){}
P (double x,double y):x(x),y(y){
}
P operator +(P p){
return P(add(x,p.x),add(y,p.y));
}
P operator -(P p){
return P(add(x,-p.x),add(y,-p.y));
}
P operator *(double d){
return P(x*d,y*d);
}
double det(P p){
return add(x*p.y,-y*p.x);
}
double dot(P p){
return add(x*p.x,y*p.y);
}
};
bool cmp(P a,P b)
{
if(a.x!=b.x)
return a.x<b.x;
return a.y<b.y;
}
P p[100000],q[100000];
int vis[100000];
int ans[100000];
P ps[1000000];
int main()
{
int T,n,l;
scanf("%d",&T);
while(T--)
{
memset(vis,0,sizeof(vis));
int k=0;
scanf("%d",&n);
int mink=0;
double mn=10000000.0;
for(int i=0;i<n;i++)
{
scanf("%d%lf%lf",&p[i].index,&p[i].x,&p[i].y);
if(mn>p[i].y)
{
mn=p[i].y;
mink=p[i].index;
}
}
sort(p,p+n,cmp);
for(int i=0;i<n;i++)
{
if(p[i].index==mink)
{
mink=i;
break;
}
}
int first=1;
int l=k;
while(1)
{
for(int i=mink,t=k;i<n;i++)
{
if(vis[p[i].index])
continue;
if(t==0) //当凸包里什么都没有时,需要先放两个点进去;如果有点则不管,因为都要满足不能右转
{
while(k>1 && (ps[k-1]-ps[k-2]).det(p[i]-ps[k-2])<0) k--;
ps[k++]=p[i];
}
else
{
while(k>t && (ps[k-1]-ps[k-2]).det(p[i]-ps[k-2])<0) k--;
ps[k++]=p[i];
}
}
for(int i=0;i<k;i++)
vis[ps[i].index]=1;
for(int i=n-2,t=k;i>=0;i--)
{
if(vis[p[i].index])
continue;
while(k>t && (ps[k-1]-ps[k-2]).det(p[i]-ps[k-2])<0) k--;
ps[k++]=p[i];
}
for(int i=0;i<k;i++)
vis[ps[i].index]=1;
if(l==k)
break;
l=k;
mink=0;
}
printf("%d",n);
for(int i=0;i<k;i++)
printf(" %d",ps[i].index);
printf("\n");
}
return 0;
}