码迷,mamicode.com
首页 > 其他好文 > 详细

POJ - 1127 Jack Straws(几何)

时间:2017-03-09 13:44:00      阅读:174      评论:0      收藏:0      [点我收藏+]

标签:几何   scanf   als   point   sig   ons   math   []   span   

题意:桌子上放着n根木棍,已知木棍两端的坐标。给定几对木棍,判断每对木棍是否相连。当两根木棍之间有公共点或可以通过相连的木棍间接的连在一起,则认为是相连的。

分析:

1、若线段i与j平行,且有部分重合,则相连。否则,求直线i与直线j交点,再判断该交点是否在两线段上,以确定是否相连。

2、flod整理一下所有的关系。

3、判断点是否在线段上:(线段i,点t)

(1)外积(l[i] - t) × (r[i] - t) = 0, 可判断点x是否在直线i上(两向量叉乘为0,两向量平行)

(2)内积(l[i] - x) · (r[i] - x) <= 0, 可判断点x是否落在l[i]与r[i]之间。(以x为顶点,l[i] - x和r[i] - x为边的角a,当内积<0----a = 180°,当内积=0,x与l[i]重合或x与r[i]重合)。

4、求两直线交点:(直线i,直线j)

(1)直线i上的某点t可表示为l[i] + w(r[i] - l[i]),w为系数

(2)点t在直线j上可表示为(l[j] - t) × (r[j] - t) = 0,由此可算出系数w,但由于t的表达式过于复杂,所以改用(r[j] - l[j]) × (t - l[j]) = 0来判断点t是否在直线j上

解得,w = ((r[j] - l[j]) × (l[j] - l[i])) / ((r[j] - l[j]) × (r[i] - l[i]))。

(3)将求出的w代入t,此时t为直线i与j的交点,但该交点不一定在线段i与j上,所以要判断后才可确定线段i与j是否相连。

#pragma comment(linker, "/STACK:102400000, 102400000")
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cctype>
#include<cmath>
#include<iostream>
#include<sstream>
#include<iterator>
#include<algorithm>
#include<string>
#include<vector>
#include<set>
#include<map>
#include<stack>
#include<deque>
#include<queue>
#include<list>
#define Min(a, b) ((a < b) ? a : b)
#define Max(a, b) ((a < b) ? b : a)
const double eps = 1e-10;
inline int dcmp(double a, double b){
    if(fabs(a - b) < eps) return 0;
    return a > b ? 1 : -1;
}
typedef long long LL;
typedef unsigned long long ULL;
const int INT_INF = 0x3f3f3f3f;
const int INT_M_INF = 0x7f7f7f7f;
const LL LL_INF = 0x3f3f3f3f3f3f3f3f;
const LL LL_M_INF = 0x7f7f7f7f7f7f7f7f;
const int dr[] = {0, 0, -1, 1, -1, -1, 1, 1};
const int dc[] = {-1, 1, 0, 0, -1, 1, -1, 1};
const int MOD = 1e9 + 7;
const double pi = acos(-1.0);
const int MAXN = 13 + 10;
const int MAXT = 10000 + 10;
using namespace std;
int vis[MAXN][MAXN];
int N;
double add(double a, double b){//考虑误差的加法运算
    if(abs(a + b) < eps * (abs(a) + abs(b))) return 0;
    return a + b;
}
struct Point{
    double x, y;
    void read(){
        scanf("%lf%lf", &x, &y);
    }
    Point(){}
    Point(double xx, double yy):x(xx), y(yy){}
    Point operator + (Point p){
        return Point(add(x, p.x), add(y, p.y));
    }
    Point operator - (Point p){
        return Point(add(x, -p.x), add(y, -p.y));
    }
    Point operator * (double t){
        return Point(x * t, y * t);
    }
    double dot(Point p){//内积
        return add(x * p.x, y * p.y);
    }
    double det(Point p){//外积
        return add(x * p.y, -y * p.x);
    }
}l[MAXN], r[MAXN];//线段的左右端点
bool onsegment(Point A, Point B, Point x){//判断点x是否在以A,B为端点的线段上
    return (A - x).det(B - x) == 0 && (A - x).dot(B - x) <= 0;
}
Point intersection(Point l1, Point r1, Point l2, Point r2){//计算直线1与直线2的交点(l1--直线1的左端点,r1--直线1的右端点)
    return l1 + (r1 - l1) * ((r2 - l2).det(l2 - l1) / (r2 - l2).det(r1 - l1));
}
bool judge(Point l1, Point r1, Point l2, Point r2){
    if(onsegment(l1, r1, l2)) return true;
    if(onsegment(l1, r1, r2)) return true;
    if(onsegment(l2, r2, l1)) return true;
    if(onsegment(l2, r2, r1)) return true;
    return false;
}
void solve(){
    for(int i = 0; i < N; ++i){
        vis[i][i] = 1;
        for(int j = 0; j < i; ++j){
            if((l[i] - r[i]).det(l[j] - r[j]) == 0){//线段i与线段j平行
                if(judge(l[i], r[i], l[j], r[j])){
                    vis[i][j] = vis[j][i] = 1;//两线段有部分重合,相连
                }
            }
            else{
                Point x = intersection(l[i], r[i], l[j], r[j]);//x为直线i与直线j的交点
                vis[i][j] = vis[j][i] = onsegment(l[i], r[i], x) && onsegment(l[j], r[j], x);//需要判断该交点是否在两个线段上
            }
        }
    }
    for(int k = 0; k < N; ++k){
        for(int i = 0; i < N; ++i){
            for(int j = 0; j < N; ++j){
                vis[i][j] |= vis[i][k] && vis[k][j];
            }
        }
    }
}
int main(){
    while(scanf("%d", &N) == 1){
        if(!N) return 0;
        memset(vis, 0, sizeof vis);
        for(int i = 0; i < N; ++i){
            l[i].read();
            r[i].read();
        }
        solve();
        int a, b;
        while(scanf("%d%d", &a, &b) == 2){
            if(!a && !b) break;
            if(vis[a - 1][b - 1]){
                printf("CONNECTED\n");
            }
            else{
                printf("NOT CONNECTED\n");
            }
        }
    }
    return 0;
}

  

POJ - 1127 Jack Straws(几何)

标签:几何   scanf   als   point   sig   ons   math   []   span   

原文地址:http://www.cnblogs.com/tyty-Somnuspoppy/p/6525066.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!