题意:有n个点,求一条有向路径(从某点到y轴的投影出发)满足:
①在路径上的点数最多
②路径只能直走或左转
③路径不自交
M组数据(1 <= M <= 10),1 <= N <= 50
题解:假设已经到达某个点,则以该点为极坐标原点,极角最小且距离最近的合法点就是下一个该走的点(由限制②和③可以看出,这样的点下一步可以走到的范围包含了其他合法点可以走到的范围)
实现时枚举出发点,判断极角使用点积;判断合法则使用叉积,并且存储一个数组,记录之前的点,判断线段相交(使用规范相交即可)与是否走到重复点。
Debug半天发现自己求极角cos值公式写错了(输出中间变量的时候就在想,怎么这些cos值绝对值这么小),忍不住笑出了声。
代码乱糟糟的
#include<cmath> #include<cstdio> #include<cstring> #include<algorithm> #include<iostream> using namespace std; #define rep(i,a,b) for (int i=a;i<=b;++i) const double eps=1e-7; struct point{ int x,y; point(){} point (int a,int b): x(a),y(b) {} friend point operator + (const point &a,const point &b){ return point(a.x+b.x,a.y+b.y); } friend point operator - (const point &a,const point &b){ return point(a.x-b.x,a.y-b.y); } friend point operator * (const int &r,const point &a){ return point(r*a.x,r*a.y); } friend bool operator == (const point &a,const point &b){ return (abs(a.x-b.x)<eps && abs(a.y-b.y)<eps); } double norm(){ return sqrt(double(x*x+y*y)); } }; inline int det(point a,point b) {return a.x*b.y-a.y*b.x;} inline int dot(point a,point b) {return a.x*b.x+a.y*b.y;} inline int dist(point a,point b) {return (a-b).norm();} inline bool seg_cross_seg(point a,point b,point c,point d) { if (min(c.x,d.x)>max(a.x,b.x) || min(a.x,b.x)>max(c.x,d.x) || min(c.y,d.y)>max(a.y,b.y) || min(a.y,b.y)>max(c.y,d.y)) return false; return det(a-c,d-c)*det(b-c,d-c)<0 && det(c-a,b-a)*det(d-a,b-a)<0; } inline int sqr(int x){return x*x;} point s[60]; int tot,ans[60],pre[60]; int n,t,x,y,T; bool ok(int now,int nxt,point b) { if (now==nxt || s[nxt]==b) return false; if (det(s[now]-b,s[nxt]-s[now])<0) return false; int j=now; while (pre[j]!=-1) { if ((j==nxt) || seg_cross_seg(s[now],s[nxt],s[pre[j]],s[j])) return false; j=pre[j]; } if (j==nxt ||seg_cross_seg(s[now],s[nxt],point(0,s[j].y),s[j])) return false; return true; } void dfs(point b,int now,int dep) { bool flag=false; double temp1=-100,temp2; int nex=-1; rep(i,1,n) if (ok(now,i,b)) { flag=true; temp2=dot(s[now]-b,s[i]-s[now])/(s[now]-b).norm()/(s[i]-s[now]).norm(); if (temp2>temp1+eps || (abs(temp2-temp1)<eps && dist(s[i],s[now])<dist(s[now],s[nex]))) { temp1=temp2; nex=i; } } if (flag) { pre[nex]=now; dfs(s[now],nex,dep+1); } else if (dep>tot) { tot=dep; int i=now,j=tot; while (i!=-1) { ans[j]=i;i=pre[i];--j; } } } int main() { scanf("%d",&T); while (T--) { scanf("%d",&n); tot=0; rep(i,1,n) scanf("%d%d%d",&t,&x,&y),s[t]=point(x,y); rep(i,1,n) { pre[i]=-1; dfs(point(0,s[i].y),i,1); } printf("%d",tot); rep(i,1,tot) printf(" %d",ans[i]); printf(" ",t); } return 0; }