【解题报告】 POJ 1556 The Doors -- 最短路问题 Dijkstra算法 + 直线相交

题目连接: POJ 1556
题目大意:从房间的坐标(0,5) -> (10,5),中间经过最多不超过18个墙,求路径最短。
这道题在 nyoj上AC不了,貌似数据中墙会重复输入 ( waiting... )
// POJ 1556 The Doors  -- 最短路问题 Dijkstra算法 + 直线相交
// PS : 自我感觉Dijkstra算法类似于 BFS
//
/*test data
2
4 2 7 8 9
7 3 4.5 6 7
1
5 4 6 7 8
5
4 0 1 2 3
4.5 0 0.5 0.8 1
5 4 6 7 8
7 2 4.6 5 6
9 1.5 2.5 5.5 7.5
-1
	
	=14.56
	 10.06
	 10.00
*/

#include <stdio.h>
#include <math.h>
#include <algorithm>
using namespace std;

const double infiniteS = 0.000001;
const int infinite = (1<<30); // 无穷大
const int MAXP = 200; //74

struct POINT{
	double x,y;
}p[MAXP];
double d[MAXP];
int n;

double Abs(double a){
	return (a>=0)?(a):(-a);
}

bool comp(POINT A,POINT B){ // 按 x 排序
	if (Abs(A.x - B.x) < infiniteS)
		return A.y < B.y;
	else
		return A.x < B.x;
}
double Distance(double x1,double y1,double x2,double y2){
	return sqrt( (x1-x2)*(x1-x2) + (y1-y2)*(y1-y2) );
}

double XJ(POINT p0,POINT p1, POINT p2,POINT p3){
	// 一般情况下计算 p0 p1 X p2 p3 的叉积
	// (p1.x-p0.x, p1.y-p0.y) vector|p0p1|
	// (p3.x-p2.x, p3.y-p2.y) vector|p2p3|
	double res = (p1.x-p0.x)*(p2.y-p0.y) - (p3.x-p2.x)*(p3.y-p2.y);
	return res;
}
int XJ(POINT p0,POINT p1, POINT p2){
	// p0 p1 p2 顺时针 为正输出1 ,否则-1 ,一条直线上为0
	// p0 p1 ->  p0 p2
	// (p1.x-p0.x, p1.y-p0.y) vector|p0p1|
	// (p2.x-p0.x, p2.y-p0.y) vector|p0p2|
	double res = (p1.x-p0.x)*(p2.y-p0.y) - (p2.x-p0.x)*(p1.y-p0.y);
	return (res > infiniteS)?(1):(-1);
}

bool Segment(POINT a, POINT b, POINT c, POINT d){
	// 说明是 1^-1=-2, 存在两个跨立则判定为线段相交
	return ((XJ(a,b,c)^XJ(a,b,d))==-2) && ((XJ(a,c,d)^XJ(b,c,d))==-2);
}

bool ExisTobstacle(int p1,int p2){ // 判断两个点之间有障碍
	double left_x = p[p1].x, right_x = p[p2].x;
	for (int i = p1 + 1; i < p2; i++){
		if (Abs(p[i].x - left_x) <= infiniteS)continue;
		if (Abs(p[i].x - right_x) <= infiniteS)break;
		POINT a,b; // a i   i+1 i+2   i+3 b 
		a.y = 0; b.y = 10;
		a.x = b.x = p[i].x;
		if (Segment(a, p[i], p[p1], p[p2]) ||
			Segment(p[i+1], p[i+2], p[p1], p[p2]) ||
			Segment(p[i+3], b, p[p1], p[p2])	){
			// 只要与墙有交点 则存在障碍
			return true;
		}
		i+=3;
	}
	return false;
}

double Dijkstra(int np){ // (0,5) -> (10,5) 的最短路
	for (int i = 0; i < np; i++){
		for (int j = i + 1; j < np; j++){
			if (p[i].x == p[j].x || ExisTobstacle(i,j) )
				continue;

			double dis = Distance(p[i].x,p[i].y,p[j].x,p[j].y);
			if (dis + d[i] < d[j]){
				d[j] = dis + d[i];
			}
		}
	}
	return d[np-1];
}

int init(int n){
	for (int i = 0; i < MAXP;i++){
		d[i] = infinite;
	}
	d[0]=0;
	p[0].x=0;p[0].y=5;
	int psub=1;
	for (int i = 0; i < n; i++){ // p[]: 0 1  2 3    4 5  6 7 ....
		double tempx;
		scanf("%lf",&tempx);
		for (int j = 0 ; j < 4; j++){
			scanf("%lf",&p[psub].y);
			p[psub++].x = tempx;
		}
	}p[psub].x = 10;	p[psub++].y = 5;
	return psub;
}

int main()
{
//	freopen("in.txt","r",stdin);

	while(scanf("%d",&n), n+1){
		if (n==0){
			printf("10.00\n");continue;
		}
		int psub = init(n);	// 初始化

		sort(&p[0],&p[n-1],comp);
		printf("%.2lf\n",Dijkstra(psub));
	}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值