POJ1556:最短路+线段相交

POJ1556

题解

  • 暴力任意两个点之间连线,判断有没有线段与之相交,没有求两点之间的距离。否则inf
  • 跑最短路,floyd方便不超时。
  • 我对点的处理有点麻烦
  • x号点和y号点之间的线段编号范围
    1列:1,2,3,4包含边1 2 3
    2列:5,6,7,8包含边4 5 6
    3列:9,10,11,12包含边7 8 9
    …………
  • 4n-3--4n点包含边3n-2--3n
  • x点对应的列好为(x+3)/4
  • 起点和终点单独处理

代码

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
#include <cmath>
using namespace std;
double const eps = 1e-8;
double const inf = 1e20;
int const N = 100;
int n,edge_cnt,point_cnt;
double mp[N][N];
typedef struct Point{   //点和向量
	double x,y;
	Point(){};
	Point(double x,double y):x(x),y(y){};
	Point operator - (const Point& e)const{   //减
		return Point(x - e.x,y - e.y);
	}
	double operator ^ (const Point& e)const{  //叉乘
		return x * e.y - y * e.x;
	}
	double operator * (const Point& e)const{
		return x * e.x + y * e.y;
	}
}Vector;
struct Line{    //直线的定义
	Point a,b;
	Line(){};
	Line(Point a,Point b):a(a),b(b){}
};
Line line[N];
Point p[N];
int dcmp(double x){    //判断符号
	if(fabs(x) < eps)	return 0;
	else return x < 0 ? -1 : 1;
}
double Distance(Point a,Point b){
	return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
}
bool onsegment(Point p,Point a1,Point a2){
	return dcmp((a1 - p) ^ (a2 - p)) == 0 && dcmp((a1 - p) * (a2 - p)) < 0;
}
bool segment_intersection(Line line1,Line line2){  //判断线段是否相交,相交返回true
	double c1 = (line1.b - line1.a) ^ (line2.a - line1.a);
	double c2 = (line1.b - line1.a) ^ (line2.b - line1.a);
	double c3 = (line2.b - line2.a) ^ (line1.a - line2.a);
	double c4 = (line2.b - line2.a) ^ (line1.b - line2.a);
	return dcmp(c1) * dcmp(c2) < 0 && dcmp(c3) * dcmp(c4) < 0;

}
void build_edge(){   //连接任意两点,没有与任意一条边相交,就加入边
	for(int i=1;i<=point_cnt;i++){
		for(int j=1;j<=point_cnt;j++){
			if(i == j)	mp[i][j] = mp[j][i] = 0;
			else 	mp[i][j] = mp[j][i] = inf;
		}
	}
	bool flag;
	int to,from;
	for(int i=1;i<=point_cnt-2;i++){
		for(int j=i+1;j<=point_cnt-2;j++){
			from = (i + 3) / 4,	to = (j + 3) /4;
			if(from == to)	continue;   //在同一列上
			flag = true;
			for(int k=3*from-2;k<=3*to && flag;k++)
				if(segment_intersection(Line(p[i],p[j]),line[k]))  flag = false;	//如果与任意一条线段相交
			if(flag)	mp[j][i] = mp[i][j] = Distance(p[i],p[j]);
		}
	}
	for(int i=1;i<=point_cnt-2;i++){   //起点和终点与中间的点连边
		flag = true;
		to = (i + 3) / 4 - 1;
		for(int j=1;j<=3*to && flag;j++)
			if(segment_intersection(Line(p[i],p[point_cnt-1]),line[j]))  flag = false;
		if(flag)	mp[point_cnt-1][i] = mp[i][point_cnt-1] = Distance(p[i],p[point_cnt-1]);
		to = (i + 3) / 4 + 1;
		flag = true;
		for(int j=3*to-2;j<=edge_cnt && flag;j++)
			if(segment_intersection(Line(p[i],p[point_cnt]),line[j]))  flag = false;	
		if(flag)	mp[point_cnt][i] = mp[i][point_cnt] = Distance(p[i],p[point_cnt]);	
	}
	flag = true;
	for(int i=1;i<=edge_cnt;i++)
		if(segment_intersection(Line(p[point_cnt],p[point_cnt-1]),line[i]))  flag = false;	
	if(flag)	mp[point_cnt][point_cnt-1] = mp[point_cnt-1][point_cnt] = Distance(p[point_cnt-1],p[point_cnt]);	
}
void Floyd(){
	for(int i=1;i<=point_cnt;i++)
	for(int j=1;j<=point_cnt;j++)
	for(int k=1;k<=point_cnt;k++)
		if(mp[i][k] < inf && mp[k][j] < inf && mp[i][k] + mp[k][j] < mp[i][j])	
			mp[i][j] = mp[i][k] + mp[k][j];
}
int main(){
	while(~scanf("%d",&n) && n != -1){
		edge_cnt = point_cnt = 0;
		for(int i=0;i<n;i++){
			double x,y1,y2,y3,y4;
			scanf("%lf%lf%lf%lf%lf",&x,&y1,&y2,&y3,&y4);
			line[++edge_cnt] = Line(Point(x,0),p[++point_cnt] = Point(x,y1));
			line[++edge_cnt] = Line(p[++point_cnt] = Point(x,y2),p[++point_cnt] = Point(x,y3));
			line[++edge_cnt] = Line(p[++point_cnt] = Point(x,y4),Point(x,10));
		}
		p[++point_cnt] = Point(0,5);
		p[++point_cnt] = Point(10,5);
		build_edge();
		Floyd();
		printf("%.2f\n",mp[point_cnt-1][point_cnt]);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_42264485/article/details/88918859
今日推荐