最近在SIAT做自己非常感兴趣的流动数据分析。做3D和纯开发久了,发现计算几何和图论的算法都稍微有点生疏,趁最近还不忙,刷几道相关的题目上下手当作复习。
poj1556,感觉这题算是计算几何题目里面的一个很经典的解体思路,最优值往往会离散在某些极限点上。就跟这题目一样,如果能够直接连接两点,ok;否则最短路径一定会经过中间墙上的四个点中某个点(可以自己枚举下几种情况)。剩下就用了Floyd的类似思想,看点i和点j的最短路径,如果i点能够直线连接j点,那么直接输出最短路径,否则就迭代看点i到点k的最短路径+点k到点j的最短路径哪个最优。
#include<iostream> #include <math.h> using namespace std; const double MAXVALUE=(double)(1<<30); double MinNumber(double x,double y) { if(x<y) { return x; } else { return y; } } double MaxNumber(double x,double y) { if(x<y) { return y; } else { return x; } } class Point { public: Point(){} Point(double tx,double ty) { x=tx; y=ty; } double x,y; }; class Segment { public: Segment(){} Segment(Point p1,Point p2) { point1=p1; point2=p2; } Point point1,point2; }; class Wall { public: double x; double y[4]; int iPointNum; }; double Distance(Point point1,Point point2) { return sqrt( pow(point1.x-point2.x,2) + pow(point1.y-point2.y,2) ); } //return (p2-p1)*(p3-p1) double Direction(Point point1,Point point2,Point point3) { Point vec1=Point(point2.x-point1.x,point2.y-point1.y); Point vec2=Point(point3.x-point1.x,point3.y-point1.y); return (vec1.x*vec2.y-vec1.y*vec2.x) ; } bool OnSegment(Point point,Segment seg) { double minX=MinNumber(seg.point1.x,seg.point2.x); double maxX=MaxNumber(seg.point1.x,seg.point2.x); double minY=MinNumber(seg.point1.y,seg.point2.y); double maxY=MaxNumber(seg.point1.y,seg.point2.y); if(point.x>=minX && point.x<=maxX && point.y>=minY && point.y<=maxY) { return true; } else { return false; } } //线段相交测试主函数 bool SegmentInteract(Segment seg1,Segment seg2) { //seg2 cross seg1 double d1=Direction(seg1.point1,seg1.point2,seg2.point1); double d2=Direction(seg1.point1,seg1.point2,seg2.point2); //seg1 cross seg2 double d3=Direction(seg2.point1,seg2.point2,seg1.point1); double d4=Direction(seg2.point1,seg2.point2,seg1.point2); if( d1*d2<0 && d3*d4<0 ) return true; else if(d1==0 && OnSegment(seg2.point1,seg1)) { return true; } else if(d2==0 && OnSegment(seg2.point2,seg1)) { return true; } else if(d3==0 && OnSegment(seg1.point1,seg2)) { return true; } else if(d4==0 && OnSegment(seg1.point2,seg2)) { return true; } return false; } //See if the seg interact with any of the walls[iStart]...........walls[iEnd] bool InteractWalls(int iStart,int iEnd,Wall walls[], Segment seg) { if(iStart>iEnd) { return false; } for(int i=iStart;i<=iEnd;i++) { bool virtualInteract=false; for(int j=0;j<4;j+=2) { if(SegmentInteract(Segment(Point(walls[i].x,walls[i].y[j]),Point(walls[i].x,walls[i].y[j+1])),seg)) { //interact with a virtual segment, so ok. virtualInteract=true; } } if(virtualInteract==false)//the seg interacts with this wall. { return true; } } return false; } int main() { Wall walls[20]; Point startPoint=Point(0.0f,5.0f); Point endPoint=Point(10.0f,5.0f); int nInterWall=0; int nPointNumber=0; double minDistance[100][100]; while(cin>>nInterWall) { if(nInterWall==-1) return 0; nPointNumber=4*nInterWall+2; //Initialize the first and last wall walls[0].iPointNum=1; walls[0].x=0.0f; walls[0].y[0]=5.0f; walls[nInterWall+1].iPointNum=1; walls[nInterWall+1].x=10.0f; walls[nInterWall+1].y[0]=5.0f; //Initialize the inter walls whose index start from 1. for(int i=1;i<=nInterWall;i++) { cin>>walls[i].x; for(int j=0;j<4;j++) cin>>walls[i].y[j]; walls[i].iPointNum=4; } //initialize the distance matrix for(int i=0;i<nPointNumber;i++) { for(int j=0;j<nPointNumber;j++) { minDistance[i][j]=MAXVALUE; } } for(int iInterNumber=0;iInterNumber<=nInterWall;iInterNumber++) { for(int istartIndex=0;istartIndex<nInterWall+2-1-iInterNumber;istartIndex++) { int igoalIndex=istartIndex+iInterNumber+1; //iterate the four points of start wall and goal wall. for(int i=0;i<walls[istartIndex].iPointNum;i++) for(int j=0;j<walls[igoalIndex].iPointNum;j++) { int sPointIndex=(istartIndex==0)?0:4*(istartIndex-1)+i+1; int ePointIndex=4*(igoalIndex-1)+j+1; if(InteractWalls(istartIndex+1,igoalIndex-1,walls,Segment(Point(walls[istartIndex].x,walls[istartIndex].y[i]),Point(walls[igoalIndex].x,walls[igoalIndex].y[j])))) { for(int iWallk=istartIndex+1;iWallk<igoalIndex;iWallk++)//iterate the inter walls between the two goal walls. { for(int iPointj=0;iPointj<4;iPointj++)//go over the four points of walls iWallk { int tmpPointIndex=4*(iWallk-1)+iPointj+1; double tmpDis=minDistance[sPointIndex][tmpPointIndex]+minDistance[tmpPointIndex][ePointIndex]; if(tmpDis<minDistance[sPointIndex][ePointIndex]) { minDistance[sPointIndex][ePointIndex]=tmpDis; } } } } else { minDistance[sPointIndex][ePointIndex]=Distance(Point(walls[istartIndex].x,walls[istartIndex].y[i]),Point(walls[igoalIndex].x,walls[igoalIndex].y[j])); } } } } //cout<<setprecision(2)<<minDistance[0][4*nInterWall+1]<<endl; printf("%.2f\n",minDistance[0][4*nInterWall+1]); } return 0; }