简单几何(直线与线段相交) POJ 1039 Pipe
题意:一根管道,有光源从入口发射,问光源最远到达的地方。
分析:黑书上的例题,解法是枚举任意的一个上顶点和一个下顶点(优化后),组成直线,如果直线与所有竖直线段有交点,则表示能穿过管道。
/************************************************
* Author :Running_Time
* Created Time :2015/10/31 星期六 10:28:12
* File Name :POJ_1039.cpp
************************************************/ #include <cstdio>
#include <algorithm>
#include <iostream>
#include <sstream>
#include <cstring>
#include <cmath>
#include <string>
#include <vector>
#include <queue>
#include <deque>
#include <stack>
#include <list>
#include <map>
#include <set>
#include <bitset>
#include <cstdlib>
#include <ctime>
using namespace std; #define lson l, mid, rt << 1
#define rson mid + 1, r, rt << 1 | 1
typedef long long ll;
const int N = 1e5 + 10;
const int INF = 0x3f3f3f3f;
const int MOD = 1e9 + 7;
const double EPS = 1e-10;
const double PI = acos (-1.0);
int dcmp(double x) { //三态函数,减少精度问题
if (fabs (x) < EPS) return 0;
else return x < 0 ? -1 : 1;
}
struct Point { //点的定义
double x, y;
Point () {}
Point (double x, double y) : x (x), y (y) {}
Point operator + (const Point &r) const { //向量加法
return Point (x + r.x, y + r.y);
}
Point operator - (const Point &r) const { //向量减法
return Point (x - r.x, y - r.y);
}
Point operator * (double p) const { //向量乘以标量
return Point (x * p, y * p);
}
Point operator / (double p) const { //向量除以标量
return Point (x / p, y / p);
}
bool operator < (const Point &r) const { //点的坐标排序
return x < r.x || (x == r.x && y < r.y);
}
bool operator == (const Point &r) const { //判断同一个点
return dcmp (x - r.x) == 0 && dcmp (y - r.y) == 0;
}
};
typedef Point Vector; //向量的定义
Point read_point(void) { //点的读入
double x, y;
scanf ("%lf%lf", &x, &y);
return Point (x, y);
}
double dot(Vector A, Vector B) { //向量点积
return A.x * B.x + A.y * B.y;
}
double cross(Vector A, Vector B) { //向量叉积
return A.x * B.y - A.y * B.x;
}
double polar_angle(Vector A) { //向量极角
return atan2 (A.y, A.x);
}
double length(Vector A) { //向量长度,点积
return sqrt (dot (A, A));
}
double angle(Vector A, Vector B) { //向量转角,逆时针,点积
return acos (dot (A, B) / length (A) / length (B));
}
Vector rotate(Vector A, double rad) { //向量旋转,逆时针
return Vector (A.x * cos (rad) - A.y * sin (rad), A.x * sin (rad) + A.y * cos (rad));
}
Vector nomal(Vector A) { //向量的单位法向量
double len = length (A);
return Vector (-A.y / len, A.x / len);
}
Point line_line_inter(Point p, Vector V, Point q, Vector W) { //两直线交点,参数方程
Vector U = p - q;
double t = cross (W, U) / cross (V, W);
return p + V * t;
}
double point_to_line(Point p, Point a, Point b) { //点到直线的距离,两点式
Vector V1 = b - a, V2 = p - a;
return fabs (cross (V1, V2)) / length (V1);
}
double point_to_seg(Point p, Point a, Point b) { //点到线段的距离,两点式
if (a == b) return length (p - a);
Vector V1 = b - a, V2 = p - a, V3 = p - b;
if (dcmp (dot (V1, V2)) < 0) return length (V2);
else if (dcmp (dot (V1, V3)) > 0) return length (V3);
else return fabs (cross (V1, V2)) / length (V1);
}
Point point_line_proj(Point p, Point a, Point b) { //点在直线上的投影,两点式
Vector V = b - a;
return a + V * (dot (V, p - a) / dot (V, V));
}
bool can_seg_seg_inter(Point a1, Point a2, Point b1, Point b2) { //判断线段相交,两点式
double c1 = cross (a2 - a1, b1 - a1), c2 = cross (a2 - a1, b2 - a1),
c3 = cross (b2 - b1, a1 - b1), c4 = cross (b2 - b1, a2 - b1);
return dcmp (c1) * dcmp (c2) < 0 && dcmp (c3) * dcmp (c4) < 0;
}
bool can_line_seg_inter(Point a1, Point a2, Point b1, Point b2) {
double c1 = cross (a2 - a1, b1 - a1), c2 = cross (a2 - a1, b2 - a1);
return dcmp (c1 * c2) <= 0;
}
bool on_seg(Point p, Point a1, Point a2) { //判断点在线段上,两点式
return dcmp (cross (a1 - p, a2 - p)) == 0 && dcmp (dot (a1 - p, a2 - p)) < 0;
}
double area_triangle(Point a, Point b, Point c) { //三角形面积,叉积
return fabs (cross (b - a, c - a)) / 2.0;
}
double area_poly(Point *p, int n) { //多边形面积,叉积
double ret = 0;
for (int i=1; i<n-1; ++i) {
ret += fabs (cross (p[i] - p[0], p[i+1] - p[0]));
}
return ret / 2;
}
/*
点集凸包,输入点的集合,返回凸包点的集合。
如果不希望在凸包的边上有输入点,把两个 <= 改成 <
*/
vector<Point> convex_hull(vector<Point> ps) {
sort (ps.begin (), ps.end ()); //x - y排序
ps.erase (unique (ps.begin (), ps.end ()), ps.end ()); //删除重复点
int n = ps.size (), k = 0;
vector<Point> qs (n * 2);
for (int i=0; i<n; ++i) {
while (k > 1 && cross (qs[k-1] - qs[k-2], ps[i] - qs[k-1]) <= 0) k--;
qs[k++] = ps[i];
}
for (int i=n-2, t=k; i>=0; --i) {
while (k > t && cross (qs[k-1] - qs[k-2], ps[i] - qs[k-1]) <= 0) k--;
qs[k++] = ps[i];
}
qs.resize (k-1);
return qs;
} struct Circle {
Point c;
double r;
Circle () {}
Circle (Point c, double r) : c (c), r (r) {}
Point point(double a) {
return Point (c.x + cos (a) * r, c.y + sin (a) * r);
}
};
struct Line {
Point p;
Vector v;
double r;
Line () {}
Line (const Point &p, const Vector &v) : p (p), v (v) {
r = polar_angle (v);
}
Point point(double a) {
return p + v * a;
}
};
/*
直线相交求交点,返回交点个数,交点保存在P中
*/
int line_cir_inter(Line L, Circle C, double &t1, double &t2, vector<Point> &P) {
double a = L.v.x, b = L.p.x - C.c.x, c = L.v.y, d = L.p.y - C.c.y;
double e = a * a + c * c, f = 2 * (a * b + c * d), g = b * b + d * d - C.r * C.r;
double delta = f * f - 4 * e * g;
if (dcmp (delta) < 0) return 0;
if (dcmp (delta) == 0) {
t1 = t2 = -f / (2 * e); P.push_back (L.point (t1));
return -1;
}
t1 = (-f - sqrt (delta)) / (2 * e); P.push_back (L.point (t1));
t2 = (-f + sqrt (delta)) / (2 * e); P.push_back (L.point (t2));
if (dcmp (t1) < 0 || dcmp (t2) < 0) return 0;
return 2;
} /*
两圆相交求交点,返回交点个数。交点保存在P中
*/
int cir_cir_inter(Circle C1, Circle C2, vector<Point> &P) {
double d = length (C1.c - C2.c);
if (dcmp (d) == 0) {
if (dcmp (C1.r - C2.r) == 0) return -1; //两圆重叠
else return 0;
}
if (dcmp (C1.r + C2.r - d) < 0) return 0;
if (dcmp (fabs (C1.r - C2.r) - d) < 0) return 0;
double a = polar_angle (C2.c - C1.c);
double da = acos ((C1.r * C1.r + d * d - C2.r * C2.r) / (2 * C1.r * d)); //C1C2到C1P1的角?
Point p1 = C1.point (a - da), p2 = C2.point (a + da);
P.push_back (p1);
if (p1 == p2) return 1;
else P.push_back (p2);
return 2;
}
/*
过点到圆的切线,返回切线条数,切线保存在V中
*/
int point_cir_tan(Point p, Circle C, Vector *V) {
Vector u = C.c - p;
double dis = length (u);
if (dis < C.r) return 0;
else if (dcmp (dis - C.r) == 0) {
V[0] = rotate (u, PI / 2); return 1;
}
else {
double ang = asin (C.r / dis);
V[0] = rotate (u, -ang);
V[1] = rotate (u, +ang);
return 0;
}
}
/*
两圆的公切线,返回公切线条数,切线短点保存在a和b中
*/
int cir_cir_tan(Circle A, Circle B, Point *a, Point *b) {
int cnt = 0;
if (A.r < B.r) {
swap (A, B); swap (a, b);
}
double d = dot (A.c - B.c, A.c - B.c);
double rsub = A.r - B.r, rsum = A.r + B.r;
if (dcmp (d - rsub) < 0) return 0; //内含
double base = polar_angle (B.c - A.c);
if (dcmp (d) == 0 && dcmp (A.r - B.r) == 0) return -1; //两圆重叠
if (dcmp (d - rsub) == 0) { //内切,一条切线
a[cnt] = A.point (base); b[cnt] = B.point (base); cnt++;
return 1;
}
//有外公切线
double ang = acos (rsub / d);
a[cnt] = A.point (base + ang); b[cnt] = B.point (base + ang); cnt++;
a[cnt] = A.point (base - ang); b[cnt] = B.point (base - ang); cnt++;
if (d == rsum) {
a[cnt] = A.point (base); b[cnt] = B.point (base + PI); cnt++;
}
else if (dcmp (d - rsum) > 0) { //两条内公切线
double ang2 = acos (rsum / d);
a[cnt] = A.point (base + ang2); b[cnt] = B.point (base + ang2 + PI); cnt++;
a[cnt] = A.point (base - ang2); b[cnt] = B.point (base - ang2 + PI); cnt++;
}
return cnt;
} Point p1[22], p2[22], p3; int main(void) {
int n;
while (scanf ("%d", &n) == 1) {
if (!n) break;
for (int i=1; i<=n; ++i) {
p1[i] = read_point ();
p2[i] = Point (p1[i].x, p1[i].y - 1);
}
bool flag = false;
double ans = p1[1].x;
for (int i=1; i<=n && !flag; ++i) {
for (int j=1; j<=n && !flag; ++j) {
if (i == j) continue;
int k;
for (k=1; k<=n; ++k) {
if (!can_line_seg_inter (p1[i], p2[j], p1[k], p2[k])) {
break;
}
}
if (k == n + 1) {
flag = true; break;
}
else if (k > max (i, j)) {
p3 = line_line_inter (p1[i], p2[j] - p1[i], p1[k-1], p1[k] - p1[k-1]);
ans = max (ans, p3.x);
p3 = line_line_inter (p1[i], p2[j] - p1[i], p2[k-1], p2[k] - p2[k-1]);
ans = max (ans, p3.x);
}
}
}
if (!flag) {
printf ("%.2f\n", ans);
}
else puts ("Through all the pipe.");
} //cout << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC << " s.\n"; return 0;
}
简单几何(直线与线段相交) POJ 1039 Pipe的更多相关文章
- 判断直线与线段相交 POJ 3304 Segments
题意:在二维平面中,给定一些线段,然后判断在某直线上的投影是否有公共点. 转化,既然是投影,那么就是求是否存在一条直线L和所有的线段都相交. 证明: 下面给出具体的分析:先考虑一个特殊的情况,即n=1 ...
- POJ 1039 Pipe【经典线段与直线相交】
链接: http://poj.org/problem?id=1039 http://acm.hust.edu.cn/vjudge/contest/view.action?cid=22013#probl ...
- POJ 1039 Pipe(直线和线段相交判断,求交点)
Pipe Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 8280 Accepted: 2483 Description ...
- POJ 1039 直线和线段相交
题意: 题意很好理解,从左边射过来的光线,最远能经过管道到右边多少距离. 分析: 光线一定经过一个上端点和一个下端点,这一点很容易想到.然后枚举上下端点即可 #include <iostream ...
- 简单几何(直线求交点) POJ 2074 Line of Sight
题目传送门 题意:从一条马路(线段)看对面的房子(线段),问连续的能看到房子全部的最长区间 分析:自己的思路WA了:先对障碍物根据坐标排序,然后在相邻的障碍物的间隔找到区间,这样还要判断是否被其他障碍 ...
- poj 3304(直线与线段相交)
传送门:Segments 题意:线段在一个直线上的摄影相交 求求是否存在一条直线,使所有线段到这条直线的投影至少有一个交点 分析:可以在共同投影处作原直线的垂线,则该垂线与所有线段都相交<==& ...
- 线段相交 poj 1066
// 线段相交 poj 1066 // 思路:直接枚举每个端点和终点连成线段,判断和剩下的线段相交个数 // #include <bits/stdc++.h> #include <i ...
- 线段相交 POJ 2653
// 线段相交 POJ 2653 // 思路:数据比较水,据说n^2也可以过 // 我是每次枚举线段,和最上面的线段比较 // O(n*m) // #include <bits/stdc++.h ...
- hdu 3304(直线与线段相交)
Segments Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 12042 Accepted: 3808 Descrip ...
随机推荐
- 数据库多张表导出到excel
数据库多张表导出到excel public static void export() throws Exception{ //声明需要导出的数据库 String dbName = "hdcl ...
- RO05 - 如何编写RemObjects SDK服务端 (Delphi Version)
转载:http://blog.csdn.net/henreash/article/details/2261134 本文档向你展示如何使用RemObjects(Delphi版)创建第一个服务.读了本文档 ...
- 运行hexo提示/usr/bin/env: node: 没有那个文件或目录
由于Ubuntu下已经有一个名叫node的库,因此Node.js在ubuntu下默认叫nodejs,需要额外处理一下. 这个时候需要人为的建立链接,很简单一句话即可! sudo ln -s `whic ...
- 【转】android中Uri.parse()用法
1,调web浏览器 Uri myBlogUri = Uri.parse("http://xxxxx.com"); returnIt = new Intent(Intent.ACTI ...
- Kth Largest Element in an Array
Find K-th largest element in an array. Notice You can swap elements in the array Example In array [9 ...
- mysql in 查询优化
2014年11月29日21:01:01 场景:有的时候查询数据库的select in 语句中会有非常多不连续的数值,会很影响查询效率 方法:将select in 查询转换成多个select betwe ...
- liunx下安装MYSQL时需要安装的相关软件的作用
2013年11月16日 14:18:39 This installs the package for MySQL server (mysql-community-server) and also pa ...
- [Android Pro] 监听Blutooth打开广播
<uses-permission android:name="android.permission.BLUETOOTH"/> <uses-permission a ...
- myeclipse2013和以后版本破解
当你下到最新版的myeclipse-blue的时候你是否会为注册激活而烦恼呢,别担心,其实激活也就那么点事儿,请遵循我如下做法就可以了: 1.运行jdk下面的cracker.jar文件来打开生成活跃码 ...
- java单例,懒汉&饿汉
* 单例模式Singleton * 应用场合:有些对象只需要一个就足够了,如皇帝 * 作用: 保证整个应用程序中某个实例有且只有一个 * 区别: 饿汉模式的特点是加载类时比较慢,但运行是比较快 ...