【POJ 1556】The Doors 判断线段相交+SPFA

黑书上的一道例题:如果走最短路则会碰到点,除非中间没有障碍。

这样把能一步走到的点两两连边,然后跑SPFA即可。

#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 100003
using namespace std;
struct Point {
	double x, y;
	Point(double _x = 0, double _y = 0) : x(_x), y(_y) {}
};
inline int dcmp(double a) {
	return (fabs(a) < 1e-6) ? 0 : (a < 0 ? -1 : 1);
}
Point operator - (Point a, Point b) {
	return Point(a.x - b.x, a.y - b.y);
}
bool operator == (Point a, Point b) {
	return dcmp(a.x - b.x) == 0 && dcmp(a.y - b.y) == 0;
}
inline double Cross(Point a, Point b) {
	return a.x * b.y - a.y * b.x;
}
inline double Dot(Point a, Point b) {
	return a.x * b.x + a.y * b.y;
}
inline bool jiao(Point d1, Point d2, Point d3, Point d4) {
	return (dcmp(Cross(d4 - d3, d1 - d3)) ^ dcmp(Cross(d4 - d3, d2 - d3))) == -2 &&
			(dcmp(Cross(d2 - d1, d3 - d1)) ^ dcmp(Cross(d2 - d1, d4 - d1))) == -2;
}
inline int bjiao(Point d1, Point d2, Point d3) {
	if (d1 == d2 || d1 == d3)
		return 1;
	if (dcmp(Cross(d2 - d1, d3 - d1)) == 0 && dcmp(Dot(d2 - d1, d3 - d1)) == -1)
		return 1;
	return 0;
}
inline double dis(Point d1, Point d2) {
	return sqrt((d2.y - d1.y) * (d2.y - d1.y) + (d2.x - d1.x) * (d2.x - d1.x));
}

struct nodeline {
	Point a, b;
	nodeline(Point _a = (0, 0) , Point _b = (0, 0)) : a(_a), b(_b) {}
} line[N];

struct node {
	int nxt, to;
	double w;
} E[N << 1];

Point a[N];
int n, cnt, lcnt, point[N], dd, q[N];
double nowx, nowy, nowy2, dist[N];
bool vis[N];

inline void ins(int x, int y, double z) {++dd; E[dd].nxt = point[x]; E[dd].to = y; E[dd].w = z; point[x] = dd;}
inline double spfa(int S, int T) {
	memset(dist, 127, sizeof(dist));
	memset(vis, 0, sizeof(vis));
	int head = 0, tail = 1;
	q[1] = S;
	vis[S] = 1;
	dist[S] = 0;
	while (head != tail) {
		++head; if (head >= N) head %= N;
		int u = q[head];
		vis[u] = 0;
		for(int tmp = point[u]; tmp; tmp = E[tmp].nxt) {
			int v = E[tmp].to;
			if (dist[u] + E[tmp].w < dist[v]) {
				dist[v] = dist[u] + E[tmp].w;
				if (!vis[v]) {
					++tail; if (tail >= N) tail %= N;
					q[tail] = v;
					vis[v] = 1;
				}
			}
		}
	}
	return dist[T];
}

inline bool check(Point d1, Point d2) {
	for(int i = 1; i <= lcnt; ++i)
		if (jiao(d1, d2, line[i].a, line[i].b))
			return 0;
	return 1;
}

int main() {
	scanf("%d", &n);
	while (n != -1) {
		cnt = 2;
		lcnt = 0;
		a[1].x = 0;
		a[1].y = 5;
		a[2].x = 10;
		a[2].y = 5;
		for(int i = 1; i <= n; ++i) {
			scanf("%lf", &nowx);
			scanf("%lf", &nowy);
			a[++cnt] = Point(nowx, nowy);
			line[++lcnt] = nodeline(Point(nowx, 0), a[cnt]);
			scanf("%lf", &nowy);
			a[++cnt] = Point(nowx, nowy);
			scanf("%lf", &nowy2);
			a[++cnt] = Point(nowx, nowy2);
			line[++lcnt] = nodeline(a[cnt - 1], a[cnt]);
			scanf("%lf", &nowy);
			a[++cnt] = Point(nowx, nowy);
			line[++lcnt] = nodeline(a[cnt], Point(nowx, 10));
		}

		memset(point, 0 , sizeof(point));
		dd = 0;
		for(int i = 1; i <= cnt; ++i)
			for(int j = i + 1; j <= cnt; ++j)
				if (check(a[i], a[j]))
					ins(i, j, dis(a[i], a[j]));
		for(int i = 1; i <= cnt; ++i)
			if (i != 2 && check(a[i], a[2]))
				ins(i, 2, dis(a[i], a[2]));
		printf("%.2lf\n", spfa(1,2));
		scanf("%d", &n);
	}
	return 0;
}

清明节机房也放假啊滚来滚去……~(~o ̄▽ ̄)~o 。。。滚来滚去……o~(_△_o~) ~。。。

时间: 2024-08-28 14:16:30

【POJ 1556】The Doors 判断线段相交+SPFA的相关文章

poj Pick-up sticks(判断线段相交)

Pick-up sticks Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 11537   Accepted: 4337 Description Stan has n sticks of various length. He throws them one at a time on the floor in a random way. After finishing throwing, Stan tries to fin

POJ 2653 Pick-up sticks (判断线段相交)

Pick-up sticks Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 10330   Accepted: 3833 Description Stan has n sticks of various length. He throws them one at a time on the floor in a random way. After finishing throwing, Stan tries to fin

POJ 1556 - The Doors 线段相交不含端点

POJ 1556 - The Doors题意:    在 10x10 的空间里有很多垂直的墙,不能穿墙,问你从(0,5) 到 (10,5)的最短距离是多少.    分析:        要么直达,要么一定是墙的边缘点之间以及起始点.终点的连线.        所以先枚举墙上每一点到其他点的直线可达距离,就是要判定该线段是否与墙相交(不含端点).        然后最短路. 1 #include <iostream> 2 #include <cstdio> 3 #include &l

简单几何(线段相交+最短路) POJ 1556 The Doors

题目传送门 题意:从(0, 5)走到(10, 5),中间有一些门,走的路是直线,问最短的距离 分析:关键是建图,可以保存所有的点,两点连通的条件是线段和中间的线段都不相交,建立有向图,然后用Dijkstra跑最短路.好题! /************************************************ * Author :Running_Time * Created Time :2015/10/24 星期六 09:48:49 * File Name :POJ_1556.cpp

POJ 1556 The Doors 线段交 dijkstra

LINK 题意:在$10*10$的几何平面内,给出n条垂直x轴的线,且在线上开了两个口,起点为$(0, 5)$,终点为$(10, 5)$,问起点到终点不与其他线段相交的情况下的最小距离. 思路:将每个开口的两端点作为一个节点,再枚举点与点间能否直接到达(判相交),以此建图求最短路. /** @Date : 2017-07-11 16:17:31 * @FileName: POJ 1556 线段交+dijkstra 计算几何.cpp * @Platform: Windows * @Author :

POJ 2826 An Easy Problem? 判断线段相交

POJ 2826 An Easy Problem?! -- 思路来自kuangbin博客 下面三种情况比较特殊,特别是第三种 G++怎么交都是WA,同样的代码C++A了 #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> using namespace std; const double eps = 1e-8;

POJ 1556 The Doors(线段交+最短路)

#include <iostream> #include <stdio.h> #include <string.h> #include <algorithm> #include <queue> #include <map> #include <vector> #include <set> #include <string> #include <math.h> using namespac

【POJ 2653】Pick-up sticks 判断线段相交

一定要注意位运算的优先级!!!我被这个卡了好久 判断线段相交模板题. 叉积,点积,规范相交,非规范相交的简单模板 用了“链表”优化之后还是$O(n^2)$的暴力,可是为什么能过$10^5$的数据? #include<cmath> #include<cstdio> #include<cstring> #include<algorithm> #define N 100005 using namespace std; struct Point { double x

POJ 1066 Treasure Hunt(线段相交&amp;&amp;转换)

Treasure Hunt 大意:在一个矩形区域内,有n条线段,线段的端点是在矩形边上的,有一个特殊点,问从这个点到矩形边的最少经过的线段条数最少的书目,穿越只能在中点穿越. 思路:需要巧妙的转换一下这个问题,因为从一个点到终点不可能"绕过"围墙,只能穿过去,所以门是否开在中点是无所谓的,只要求四周线段中点到终点的线段与墙的最少交点个数即可.更进一步,实际上,只需判断四周围墙的所有点与终点的连线与内墙的最少交点加一即可. struct Point{ double x, y; } A,