poj1741,POJ - 1127 Jack Straws(幾何)

 2023-11-07 阅读 26 评论 0

摘要:題意:桌子上放著n根木棍,已知木棍兩端的坐標。給定幾對木棍,判斷每對木棍是否相連。當兩根木棍之間有公共點或可以通過相連的木棍間接的連在一起,則認為是相連的。 分析: 1、若線段i與j平行,且有部分重合,則相連。否則ÿ

題意:桌子上放著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;
}

  

轉載于:https://www.cnblogs.com/tyty-Somnuspoppy/p/6525066.html

版权声明:本站所有资料均为网友推荐收集整理而来,仅供学习和研究交流使用。

原文链接:https://hbdhgg.com/2/167238.html

发表评论:

本站为非赢利网站,部分文章来源或改编自互联网及其他公众平台,主要目的在于分享信息,版权归原作者所有,内容仅供读者参考,如有侵权请联系我们删除!

Copyright © 2022 匯編語言學習筆記 Inc. 保留所有权利。

底部版权信息