题目大意:
不能向左拐 不能重复走
就是求一个螺旋凸包
把已经是凸包内的点标记一下就行
因为凸包的性质 所有点都能走到
注意起点的选择 还有 反复求凸包的过程中边界的改变
#include <cstdio> #include <algorithm> #include <string.h> #include <cmath> using namespace std; const int N=55; const double eps=1e-10; 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 id; P(){}; P(double _x,double _y,int _id):x(_x),y(_y),id(_id){} P operator -(P p) { return P(add(x,-p.x),add(y,-p.y),0); }; P operator +(P p) { return P(add(x,p.x),add(y,p.y),0); }; P operator *(double d) { return P(x*d,y*d,0); }; double dot(P p) { return add(x*p.x,y*p.y); }; double det(P p) { return add(x*p.y,-y*p.x); }; }p[N], ans[N]; bool flag[N]; int n; bool cmp(P a,P b) { if(a.x==b.x) return a.y<b.y; return a.x<b.x; } void solve(int st) { memset(flag,0,sizeof(flag)); int k=0, t=1; while(k<n) { for(int i=st;i<n;i++) if(flag[p[i].id]==0) { while(k>t && (ans[k-1]-ans[k-2]).det(p[i]-ans[k-1])<=0) k--, flag[ans[k].id]=0; ans[k++]=p[i]; flag[p[i].id]=1; } t=k; for(int i=n-2;i>=0;i--) if(flag[p[i].id]==0) { while(k>t && (ans[k-1]-ans[k-2]).det(p[i]-ans[k-1])<=0) k--, flag[ans[k].id]=0; ans[k++]=p[i]; flag[p[i].id]=1; } t=k; st=0; // 注意边界的修改 } } int main() { int t; scanf("%d",&t); while(t--) { scanf("%d",&n); double miny=150.0; for(int i=0;i<n;i++) { scanf("%d%lf%lf",&p[i].id,&p[i].x,&p[i].y); miny=min(miny,p[i].y); } sort(p,p+n,cmp); int t; /// 起点应该取最低的一点 即y最小的一点 for(int i=0;i<n;i++) if(p[i].y==miny) t=i; solve(t); printf("%d ",n); for(int i=0;i<n;i++) printf("%d ",ans[i].id); printf("\n"); } return 0; }
原文地址:https://www.cnblogs.com/zquzjx/p/9612443.html
时间: 2024-11-13 10:57:49