题意:
有一只类似于蚂蚁之类的动物,由于 他的身体缺陷只可以左转不可右转,每天他它都要吃一个植物才可以活下去,如果没有食物可以吃了他就死,给你植物的坐标你要求的就是问他怎么选择吃食物的顺序才可以使自己活得长久。
最开始他的坐标在(0,y),y是所有节点中纵坐标的最小值,所以第一个食物我i们直着走过去不用转弯就可以吃到。
思路:
因为只可以左转不可以右转所以我们每次吃的都应该是转的角度最小的那个,因为只有这样我们才可以吃到更多的食物。因为这个特性我们就像到凸包, 外面的凸包就是外面这几个点的顺序,用一个数组做一下标记,标记一下这个食物是否已经被吃过, 然后对没吃过的食物继续求凸包即可,但是在求凸包的时候应该注意的一个点就是每一次求极角排序的的参照点应该是上一个凸包结果的最后一个点。
还有细节部分看一下代码注释。
G++ AC 代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
const double eps = 1e-8;
const int maxn = 110;
int vis[maxn];
int sgn(double x){
if(fabs(x)<0)return 0;
if(x<0)return -1;
return 1;
}
struct Point {
double x,y;
int num; //点的标号
Point (){};
Point (double _x,double _y){
x=_x,y=_y;
}
void input(){
scanf("%d %lf %lf",&num,&x,&y);
}
bool operator == (Point b)const{
return sgn(x-b.x)==0&&sgn(y-b.y)==0;
}
double operator ^ (const Point &b)const{
return x*b.y-y*b.x;//返回模长 带正负
}
bool operator < (Point b)const{
return sgn(x-b.x)==0?sgn(y-b.y)<0:x<b.x;
}
Point operator - (const Point &b)const{
return Point(x-b.x,y-b.y);
}
double distance (Point p){
return hypot(x-p.x,y-p.y);
}
};
struct polygon{
int n;
Point p[maxn];
struct cmp{
Point p;
cmp(const Point &p0){
p=p0;
}
bool operator () (const Point &aa,const Point &bb){
Point a=aa,b=bb;
int d=sgn((a-p)^(b-p));
if(d==0){
return sgn(a.distance(p)-b.distance(p))<0;
}
return d>0;
}
};
void norm(Point mi){ //mi直接表示的就是求凸包的基础点
sort(p+1,p+n,cmp(mi));
}
void Graham(polygon &convex,Point k){
norm(k);
int &top=convex.n;
top=0;
if(n==1){
top=1;
convex.p[0]=p[0];
return ;
}
if(n==2){
top=2;
convex.p[0]=p[0];
convex.p[1]=p[1];
if(convex.p[0]==convex.p[1])top--;
return ;
}
convex.p[0]=p[0];
convex.p[1]=p[1];
top=2;
for(int i=2;i<n;i++){
while(top>1&&sgn((convex.p[top-1]-convex.p[top-2])^(p[i]-convex.p[top-2]))<=0)
top--;
convex.p[top++]=p[i];
}
if(convex.n==2&&(convex.p[0]==convex.p[1]))convex.n--;
}
};
polygon a,ap,tempa;
int main(){
int t;
scanf("%d",&t);
while(t--){
int n;
int cnt=0,cnt1=0,cont=maxn;
scanf("%d",&n);
int ans[maxn];
for(int i=0;i<n;i++){
vis[i]=0;
tempa.p[i].input();
}
tempa.n=n;
a=tempa;
Point kk = a.p[0];
int g=0;
for(int i=1;i<n;i++){
if(sgn(a.p[i].y-kk.y)<0){
kk=a.p[i];
g=i;
}
else if(sgn(a.p[i].y-kk.y)==0&&sgn(a.p[i].x-kk.x)<0){
kk=a.p[i];
g=i;
}
}//找到第一个食物节点。
//以此作为求解凸包的基础。
swap(a.p[g],a.p[0]);
while(cont>0){
a.Graham(ap,kk);
cont=0;
//cout<<ap.n<<endl;
//对凸包内的的点做标记
if(cnt1==0){
for(int i=0;i<ap.n;i++){
ans[cnt++]=ap.p[i].num;
for(int j=0;j<tempa.n;j++){
if(ap.p[i].num==tempa.p[j].num){
vis[j]=1;
break;
}
}
}
}
else{
for(int i=1;i<ap.n;i++){
ans[cnt++]=ap.p[i].num;
for(int j=0;j<tempa.n;j++){
if(ap.p[i].num==tempa.p[j].num){
vis[j]=1;
break;
}
}
}
}
//准备节点左线一次凸包。
for(int i=0;i<tempa.n;i++){
if(!vis[i]){
a.p[++cont]=tempa.p[i];
}
}
if(cnt1==0)
cnt1+=ap.n;
else cnt1+=(ap.n-1);
a.n=cont+1;
kk=ap.p[ap.n-1];
a.p[0]=kk;
}
printf("%d",cnt1);
for(int i=0;i<cnt;i++){
printf(" %d",ans[i]);
}
printf("\n");
}
return 0;
}