成吨的细节。。。
就是找右转得最厉害的线段,然后沿着这个线段跑到最近的路口。
那如何找右转得最厉害的线段呢?就是枚举所有可能的下一个点,然后取其中最优的那个即可。
那如何判断哪个最优呢?
我是分类讨论
设上一个点是LAST,这一个点是NOW。
那么我目前的朝向就是V=NOW-LAST。
设两个点A,B。
如果A,B分别是左转和右转,那就选B。
否则如果A扭头,我就选B。
否则如果B扭头,我就选A。
否则如果B相对A右转,我就选B。
否则我选A。
那如何找最近的路口呢?就是枚举路上的所有路口,然后取其中最近的那个即可。
那如何判断最近呢?
直接两点间距离公式即可。
主要是难在很多琐碎的细节需要讨论清楚,否则就会找错方向和路口,从而出错或者陷入死循环。
debug浪费了非常多的时间,如果能完全想清楚再下手写代码就好了。
就是仅仅有大致思路是不够的,尽量把实现的细节都完全弄明白,具体到这个功能块每一步该怎么做,可以拿张纸写下具体过程,然后证明正确了再动手写代码。否则等到你写的时候就会比较无暇顾及细节,容易出错,而且没有那种对程序精细的掌控感。一旦出bug的话就会很不知所措,只能慢吞吞地单步调试。
再次通过自己带数据查出bug。这个方法真的很强.。但是这毕竟治标不治本。这方法不但速度有点慢,而且还得看运气。想办法提升自己的代码AC率才是提升自己的根本方法。既要学会使用技巧也要想办法提升自己。
代码
#include<bits/stdc++.h>
using namespace std;
struct Point
{
double x,y;
Point(double x=0,double y=0):x(x),y(y){}
void Read()
{
scanf("%lf %lf",&x,&y);
}
bool operator < (const Point& rhs) const
{
return x<rhs.x||(x==rhs.x&&y<rhs.y);
}
};
typedef Point Vector;
const double eps = 1e-10;
int dcmp(double x)
{
if(fabs(x)<eps) return 0;
return x<0?-1:1;
}
Point operator + (Point A,Vector B)
{
return Point(A.x+B.x,A.y+B.y);
}
Vector operator - (Point A,Point B)
{
return Vector(A.x-B.x,A.y-B.y);
}
Vector operator * (Vector V,double t)
{
return Vector(V.x*t,V.y*t);
}
bool operator == (Point A,Point B)
{
return dcmp(A.x-B.x)==0&&dcmp(A.y-B.y)==0;
}
bool operator != (Point A,Point B)
{
return dcmp(A.x-B.x)!=0||dcmp(A.y-B.y)!=0;
}
double Dot(Vector A,Vector B)
{
return A.x*B.x+A.y*B.y;
}
double Cross(Vector A,Vector B)
{
return A.x*B.y-A.y*B.x;
}
double Len(Vector V)
{
return sqrt(Dot(V,V));
}
double Dist(Point A,Point B)
{
return Len(A-B);
}
Point GetIntersection(Point A,Point B,Point C,Point D)
{
Vector V1=B-A;
Vector V2=D-C;
Vector V3=C-A;
double t=Cross(V3,V2)/Cross(V1,V2);
return A+V1*t;
}
bool OnSegment(Point P,Point A,Point B)
{
Vector V1=A-P;
Vector V2=B-P;
return dcmp(Len(V1))==0||dcmp(Len(V2))==0||(dcmp(Cross(V1,V2))==0&&dcmp(Dot(V1,V2))<0);
}
bool SegmentIntersection(Point A,Point B,Point C,Point D)
{
if(dcmp(Cross(B-A,D-C))==0) return false;
if(OnSegment(A,C,D)||OnSegment(B,C,D)||OnSegment(C,A,B)||OnSegment(D,A,B)) return true;
Vector V1=C-A;
Vector V2=D-A;
Vector V3=A-C;
Vector V4=B-C;
return dcmp(Cross(B-A,V1))*dcmp(Cross(B-A,V2))<0&&dcmp(Cross(D-C,V3))*dcmp(Cross(D-C,V4))<0;
}
const int maxn = 110;
int n;
Point P[maxn];
Point Poly[maxn*maxn];
int cnt;
Point s;
Point last,now;
bool cmp1(Point A,Point B)
{
return dcmp(Dist(last,A)-Dist(last,B))>0;
}
bool cmp2(Point A,Point B)
{
Vector V1=A-now;
Vector V2=B-now;
Vector V3=now-last;
if(dcmp(Cross(V3,V1))*dcmp(Cross(V3,V2))<0) return dcmp(Cross(V3,V2))<0;
else if(dcmp(Cross(V3,V2))==0&&dcmp(Dot(V3,V2))<0) return false;
else if(dcmp(Cross(V3,V1))==0&&dcmp(Dot(V3,V1))<0) return true;
return dcmp(Cross(V1,V2))<=0;
}
int main()
{
while(~scanf("%d",&n))
{
s=Point(200,200);
for(int i=0;i<n;i++)
{
P[i].Read();
if(P[i]<s) s=P[i];
}
last=s;
last.x-=10;
now=s;
Point Next;
cnt=0;
while(1)
{
Poly[cnt++]=now;
bool you=false;
for(int i=0;i<n;i++)
if(OnSegment(now,P[i],P[(i+1)%n]))
{
if(!OnSegment(P[i],now,last)&&(!you||cmp2(Next,P[i]))) Next=P[i],you=true;
if(!OnSegment(P[(i+1)%n],now,last)&&(!you||cmp2(Next,P[(i+1)%n]))) Next=P[(i+1)%n],you=true;
}
for(int i=0;i<n;i++)
if(SegmentIntersection(now,Next,P[i],P[(i+1)%n]))
{
Point Temp=GetIntersection(now,Next,P[i],P[(i+1)%n]);
if(Temp!=now) Next=Temp;
}
if(Next==s) break;
last=now;
now=Next;
}
printf("%d\n",cnt);
for(int i=0;i<cnt;i++)
printf("%lf %lf\n",Poly[i].x,Poly[i].y);
}
return 0;
}