HDU 1154 (平面几何 点在多边形内)
2016-06-22 22:12
323 查看
题目链接:点击这里
题意:求一条直线在多边形内部的长度.
找到所有的交点, 去重以后是直线上的一系列的点. 然后相邻两个点构成的线段如果是多边形内部的或者多边形上的那就加上这个长度. 判断相邻点构成的线段是不是需要加上只需要判断中点在不在多边形内部(边界)就好了.
#include <cstdio> #include <cmath> #include <algorithm> #include <iostream> #include <vector> using namespace std; const double eps = 1e-8; const double INF = 1e20; const double pi = acos (-1.0); int dcmp (double x) { if (fabs (x) < eps) return 0; return (x < 0 ? -1 : 1); } inline double sqr (double x) {return x*x;} //*************点 struct Point { double x, y; Point (double _x = 0, double _y = 0):x(_x), y(_y) {} void input () {scanf ("%lf%lf", &x, &y);} void output () {printf ("%.2f %.2f\n", x, y);} bool operator == (const Point &b) const { return (dcmp (x-b.x) == 0 && dcmp (y-b.y) == 0); } bool operator < (const Point &b) const { return (dcmp (x-b.x) == 0 ? dcmp (y-b.y) < 0 : x < b.x); } Point operator + (const Point &b) const { return Point (x+b.x, y+b.y); } Point operator - (const Point &b) const { return Point (x-b.x, y-b.y); } Point operator * (double a) { return Point (x*a, y*a); } Point operator / (double a) { return Point (x/a, y/a); } double len2 () {//返回长度的平方 return sqr (x) + sqr (y); } double len () {//返回长度 return sqrt (len2 ()); } }; double cross (Point a, Point b) {//叉积 return a.x*b.y-a.y*b.x; } double dot (Point a, Point b) {//点积 return a.x*b.x + a.y*b.y; } double dis (Point a, Point b) {//两个点的距离 Point p = b-a; return p.len (); } double rad_degree (double rad) {//弧度转化为角度 return rad/pi*180; } double rad (Point a, Point b) {//两个向量的夹角 return fabs (atan2 (fabs (cross (a, b)), dot (a, b)) ); } bool parallel (Point a, Point b) {//向量平行 double p = rad (a, b); return dcmp (p) == 0 || dcmp (p-pi) == 0; } //************直线 线段 struct Line { Point s, e;//直线的两个点 Line () {} Line (Point _s, Point _e) : s(_s), e(_e) {} //一个点和倾斜角确定直线 Line (Point p, double ang) { s = p; if (dcmp (ang-pi/2) == 0) { e = s + Point (0, 1); } else e = s + Point (1, tan (ang)); } //ax+by+c=0确定直线 Line (double a, double b, double c) { if (dcmp (a) == 0) { s = Point (0, -c/b); e = Point (1, -c/b); } else if (dcmp (b) == 0) { s = Point (-c/a, 0); e = Point (-c/a, 1); } else { s = Point (0, -c/b); e = Point (1, (-c-a)/b); } } void input () { s.input (); e.input (); } }; int relation (Point p, Line l) {//点和直线的关系 //1:在左侧 2:在右侧 3:在直线上 int c = dcmp (cross (p-l.s, l.e-l.s)); if (c < 0) return 1; else if (c > 0) return 2; else return 3; } bool point_on_seg (Point p, Line l) {//判断点在线段上 return dcmp (cross (p-l.s, l.e-l.s)) == 0 && dcmp (dot (p-l.s, p-l.e) <= 0); //如果忽略端点交点改成小于号就好了 } bool parallel (Line a, Line b) {//直线平行 return parallel (a.e-a.s, b.e-b.s); } int seg_cross_seg (Line a, Line v) {//线段相交判断 //2:规范相交 1:不规范相交 0:不相交 int d1 = dcmp (cross (a.e-a.s, v.s-a.s)); int d2 = dcmp (cross (a.e-a.s, v.e-a.s)); int d3 = dcmp (cross (v.e-v.s, a.s-v.s)); int d4 = dcmp (cross (v.e-v.s, a.e-v.s)); if ((d1^d2) == -2 && (d3^d4) == -2) return 2; return (d1 == 0 && dcmp (dot (v.s-a.s, v.s-a.e)) <= 0) || (d2 == 0 && dcmp (dot (v.e-a.s, v.e-a.e)) <= 0) || (d3 == 0 && dcmp (dot (a.s-v.s, a.s-v.e)) <= 0) || (d4 == 0 && dcmp (dot (a.e-v.s, a.e-v.e)) <= 0); } int line_cross_seg (Line a, Line v) {//直线和线段相交判断 a直线v线段 //2:规范相交 1:非规范相交 0:不相交 int d1 = dcmp (cross (a.e-a.s, v.s-a.s)); int d2 = dcmp (cross (a.e-a.s, v.e-a.s)); if ((d1^d2) == -2) return 2; return (d1 == 0 || d2 == 0); } int line_cross_line (Line a, Line v) {//直线相交判断 //0:平行 1:重合 2:相交 if (parallel (a, v)) return relation (a.e, v) == 3; return 2; } Point line_intersection (Line a, Line v) {//直线交点 //调用前确保有交点 double a1 = cross (v.e-v.s, a.s-v.s); double a2 = cross (v.e-v.s, a.e-v.s); return Point ((a.s.x*a2-a.e.x*a1)/(a2-a1), (a.s.y*a2-a.e.y*a1)/(a2-a1)); } bool relation (Point q, Point *p, int n) {//点和多边形的关系(凸凹都可以) //0:外部 1:内部 2:边上 3:顶点 for (int i = 0; i < n; i++) { if (p[i] == q) return 3; } for (int i = 0; i < n; i++) { if (point_on_seg (q, Line (p[i], p[(i+1)%n]))) return 2; } int cnt = 0; for (int i = 0; i < n; i++) { int j = (i+1)%n; int k = dcmp (cross (q-p[j], p[i]-p[j])); int u = dcmp (p[i].y-q.y); int v = dcmp (p[j].y-q.y); if (k > 0 && u < 0 && v >= 0) cnt++; if (k < 0 && v < 0 && u >= 0) cnt--; } return cnt != 0; } #define maxn 11111 int n, m; Point p[maxn], q[maxn], ans[maxn]; Line l[maxn]; int cnt; int main () { while (scanf ("%d%d", &n, &m) == 2 && n+m) { for (int i = 0; i < n; i++) { p[i].input (); } while (m--) { Line l; l.input (); cnt = 0; double res = 0; for (int i = 0; i < n; i++) { int j = (i+1)%n; int cur = 0; if (relation (p[i], l) == 3) ans[cnt++] = p[i], cur++; if (relation (p[j], l) == 3) ans[cnt++] = p[j], cur++; if (line_cross_seg (l, Line (p[j], p[i])) == 2) { Point pp = line_intersection (l, Line (p[j], p[i])); ans[cnt++] = pp; } } sort (ans, ans+cnt); int cur = 0; for (int i = 0; i < cnt; i++) { if (i && ans[i] == ans[i-1]) continue; else ans[cur++] = ans[i]; } cnt = cur; for (int i = 0; i < cnt-1; i++) { int j = i+1; if (relation ((ans[i]+ans[j])/2, p, n)) res += dis (ans[i], ans[j]); } printf ("%.3f\n", res); } } return 0; }
相关文章推荐
- sql语句中any和all的用法
- MemCached的安装和JAVA客户端连接Memcached示例代码
- 【软件工程】持续集成:如何建立百万行级代码的版本构建系统(四)项目管理
- 3 大型网站核心架构要素
- GeoIP2 精准服务(网络API)
- LeetCode-9-Palindrome Number
- 4-5 链式表操作集
- leetcode :Implement strStr()
- 网址记录
- 238. Product of Array Except Self
- HTTP基础知识普及
- 微商
- innodb_flush_log_at_trx_commit
- 获取历史市盈率的地方
- Leetcode - Two Sum
- 个人总结
- Android虚线
- Problem D
- Jfinal 入门
- 【NodeJs环境下bower】如何更改bower_components文件夹的位置