Poj1556线段相交判断+动规最短路

  最近在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;
}


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值