说下当时自己的证明(后来有人说这是个所谓极角排序问题,Anyway思路差不多,有点贪心意思,顺带考察了叉积应用),问题可以归结为如果这个虫来到点A,它应该选择的下一个plant的点的原则是?
我们可以证明如果点A能够经点B,左转到点C,那么点A就应该选择跳到点B。
证明:
主要证明从点A跳到点B,虫子可以选择的后续点比跳到点C更加多。
(1 ) 如果点A跳到点C,那么点B就无法再到达。但是跳到点B,却可以再跳到点C. 所以从A 到点B的路径至少比从A跳到C的路径多了一个B。
(2) 点A跳到点C,后面所有可能的可以跳到的点,比如点D,从点A跳到点B后,也一样可以到达。证明:点D在边AC的左侧,边AC在AB的左侧,所以点D也在AB的左侧,所以点D可以从B到达。
由此我们可以定义一个 点极角大小关系 B >a C (如果点A能从点B到点C)。 至于如何从程序判断,就一个简单的叉积 BA * CA ,如果大于0,说明边BA左转到边CA,B >a C.
所以问题的算法最终变成了:从规定的第一个y值最小的点A开始,不断找后面对于当前点A的极角最大的点B(就一个排序)。
#include <iostream> #include<stdio.h> #include <cmath> #include <algorithm> using namespace std; class Point { public: Point(double tmpx,double tmpy,double tId) { x=tmpx; y=tmpy; id=tId; } Point(double tmpx,double tmpy) { x=tmpx; y=tmpy; } Point() { x=0.0f; y=0.0f; } double x,y; int id; }; //Returen (p2-p1)*(p3-p1) double CrossProduct(Point point1,Point point2,Point point3) { Point vec1=Point(point1.x-point3.x,point1.y-point3.y); Point vec2=Point(point2.x-point3.x,point2.y-point3.y); return (vec1.x*vec2.y-vec1.y*vec2.x); } double Distance(Point p1,Point p2) { //double dis=abs(p1.x-p2.x)+abs(p1.y-p2.y); double dis=sqrt(pow(p1.x-p2.x,2) + pow(p1.y-p2.y,2) ); return dis; } Point currentPoint; //See if p1 can reach p2 starting from p3, or reverse //If p1>p2 (p1 can reach p2 through p3), return 1;else return -1; bool PointReachable(Point point1, Point point2) { double d = CrossProduct(point1,point2, currentPoint); if(d>0)//p1 reach p2,p1 is better { return true; } else if(d<0) { return false; } else// p1,p2,p3 are in the same line. { double dis1=Distance(point1,currentPoint); double dis2=Distance(point2,currentPoint); if(dis1<dis2) return true; else return false; } } int main() { int iCases=0; Point plantPoints[60]; Point sortedPoints[60][60]; scanf("%d",&iCases); while(iCases>0) { int iPoints=0; scanf("%d",&iPoints); double minx=(double)(1<<30); double minY=(double)(1<<30); int firstIndex=-1; for(int i=1;i<=iPoints;i++) { int tmpi; scanf("%d",&tmpi); scanf("%lf%lf",&plantPoints[tmpi].x,&plantPoints[tmpi].y); plantPoints[tmpi].id=tmpi; if(plantPoints[tmpi].y<=minY) { if(plantPoints[tmpi].y<minY || plantPoints[tmpi].x<minx) { minY=plantPoints[tmpi].y; minx=plantPoints[tmpi].x; firstIndex=tmpi; } } } //Swap Point tmpPoint=plantPoints[1]; plantPoints[1]=plantPoints[firstIndex]; plantPoints[firstIndex]=tmpPoint; printf("%d %d",iPoints,firstIndex); currentPoint=plantPoints[1]; //Find plantPoints[i]'s best next point. for(int i=2;i<iPoints;i++) { sort(plantPoints+i,plantPoints+iPoints+1,PointReachable); currentPoint=plantPoints[i]; printf(" %d",plantPoints[i].id); } if(iPoints>1) printf(" %d",plantPoints[iPoints].id); printf("\n"); iCases--; } return 0; }