日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

判断线段相交(hdu1558 Segment set 线段相交+并查集)

發布時間:2024/4/14 编程问答 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 判断线段相交(hdu1558 Segment set 线段相交+并查集) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

先說一下題目大意:給定一些線段,這些線段順序編號,這時候如果兩條線段相交,則把他們加入到一個集合中,問給定一個線段序號,求在此集合中有多少條線段。

這個題的難度在于怎么判斷線段相交,判斷玩相交之后就是怎么找個他們之間的聯系,這時候就要用到并查集了。

步驟:

1.判斷兩條線段相交

2. 用并查集實現查找線段個數和添加到集合中

關于這個判斷線段相交的問題。我搞了一晚上加上一下午,剛開始自己想了一種數學上的相交,就是先求出兩條線段所在的線性方程,然后求出他們的交點,最后在判斷這個交點在不在這兩個線段之間。這種方式剛開始一想挺簡單的,但是在判斷在不在兩個線段之間就顯得比較麻煩了,而且剛開始還漏了一種情況,就是在他們斜率不存在時怎么求出方程來,當時沒有考慮這一點直接wa了,后來又加上了這種情況才AC了。

還有一種方法就是利用向量來判定線段是否相交,這個我是看的算法導論上的,答題思路就是判斷其中一條線段是否橫跨另一條線段,如果這兩條線段都互相橫跨另一條,那么一定相交,當然還有邊界條件,就是這個交點是邊界在線段的終點的情況,那具體怎么判斷一條線段是否橫跨另外一條線段呢,這時候用到向量了,兩個向量p1,p2,如果他們的叉乘積大于0,就說明p1位于p2的逆時針的方向,小于0順時針,等于0共線。所以這一步很關鍵。當解決了這個問題之后,那么就好辦了,如果一條線段的一個點在順時針側,一個點在逆時針側,那么這條線段橫跨另一條直線,注意是直線,還不是線段,如果同時另外一條線段也橫跨這一條,那么這時就是兩個線段相互橫跨了,就是相交了。還有一個關鍵點就是在邊界情況下(就是一條線段的一個端點在另一條線段上的時候)怎么辦,這時候用到上面寫好的函數來判斷,如果返回值是0,那么就是臨界條件,這時候判斷其中一個端點和另外一條線段的關系就行了,如果都不滿足上面的這些情況,肯定是不相交了。

還有一點需要注意,在利用并查集實現的時候,要用兩個,一個是普通的并查集來存放它們之間的關系,還有一個是存放它們當前集合的數目。具體代碼如下;

代碼一(第一種判斷線段相交的方式)(后來證明可能有些數據過不了,不建議用這個)

1 #include<iostream> 2 #include <cstdio> 3 #include <cstring> 4 #define EPS 1e-8 5 using namespace std; 6 const int N = 1005; 7 struct point{ 8 double x, y; 9 }; 10 struct segmnt{ 11 point ori, des; 12 }; 13 int father[N], num[N];//father用來保存相交的線段的集合,num表示當前線段所在集合有多少條線段 14 segmnt seg[N]; 15 //初始化 16 void init(int n) 17 { 18 19 for (int i = 1; i <= n; i++) 20 { 21 father[i] = i; 22 num[i] = 1; 23 } 24 } 25 //判斷線段是否相交 26 bool is_Cross(segmnt s1, segmnt s2) 27 { 28 point p1, p2, p3, p4; 29 p1 = s1.ori; p2 = s1.des; 30 p3 = s2.ori; p4 = s2.des; 31 //當第一條線段斜率不存在,第二條斜率存在時 32 if (p1.x == p2.x && p3.x != p4.x) 33 { 34 double k = (p4.y - p3.y) / (p4.x - p3.x); 35 double y = k * (p1.x - p3.x) + p3.y; 36 return ((y - p1.y >= EPS && y - p2.y <= EPS) || (y - p1.y <= EPS && y - p2.y >= EPS)); 37 } 38 //當第一條線段斜率存在,第二條斜率不存在時 39 else if (p3.x == p4.x && p1.x != p2.x) 40 { 41 double k = (p2.y - p1.y) / (p2.x - p1.x); 42 double y = k * (p3.x - p1.x) + p1.y; 43 return ((y - p3.y >= EPS && y - p4.y <= EPS) || (y - p3.y <= EPS && y - p4.y >= EPS)); 44 } 45 //當第一條第二條斜率都不存在時 46 else if (p1.x == p2.x && p3.x == p4.x) 47 { 48 return p1.x == p3.x; 49 } 50 //當他們斜率都存在時,先求出方程,然后求出他們的交點,判斷交點是否在兩條線段上 51 double k1 = (s1.des.y - s1.ori.y) / (s1.des.x - s1.ori.x); 52 double k2 = (s2.des.y - s2.ori.y) / (s2.des.x - s2.ori.x); 53 double x0 = (k1 * s1.ori.x - k2 * s2.ori.x + s2.ori.y - s1.ori.y) / (k1 - k2); 54 double y0 = k1 * (x0 - s1.ori.x) + s1.ori.y; 55 if (((x0 >= s1.ori.x && x0 <= s1.des.x) || (x0 >= s1.des.x && x0 <= s1.ori.x)) && ((y0 >= s1.ori.y && y0 <= s1.des.y) || (y0 >= s1.des.y && y0 <= s1.ori.y)) && ((x0 >= s2.ori.x && x0 <= s2.des.x) || (x0 >= s2.des.x && x0 <= s2.ori.x)) && ((y0 >= s2.ori.y && y0 <= s2.des.y) || (y0 >= s2.des.y && y0 <= s2.ori.y))) 56 return true; 57 return false; 58 } 59 //并查集查找 60 int find(int x) 61 { 62 while (x != father[x]) 63 x = father[x]; 64 return x; 65 } 66 //合并 67 void merge(int a, int b) 68 { 69 int ta = find(a); 70 int tb = find(b); 71 if (ta != tb) 72 { 73 father[ta] = tb; 74 num[tb] += num[ta]; 75 } 76 } 77 int main() 78 { 79 int t, n; 80 scanf("%d", &t); 81 while (t--) 82 { 83 int index = 0; 84 scanf("%d", &n); 85 init(n); 86 char option; 87 for (int i = 0; i < n; i++) 88 { 89 getchar(); 90 scanf("%c", &option); 91 if (option == 'P') 92 { 93 ++index; 94 scanf("%lf %lf %lf %lf", &seg[index].ori.x, &seg[index].ori.y, &seg[index].des.x, &seg[index].des.y); 95 for (int i = 1; i < index; i++) 96 if (is_Cross(seg[i], seg[index])) 97 merge(i, index); 98 } 99 else 100 { 101 int k; 102 scanf("%d", &k); 103 printf("%d\n", num[find(k)]); 104 } 105 } 106 if (t) 107 puts(""); 108 } 109 return 0; 110 } View Code

代碼二(第二種判斷線段相交方式)

1 #include<iostream> 2 #include <cstdio> 3 #include <cstring> 4 using namespace std; 5 const int N = 1005; 6 struct point{ 7 double x, y; 8 }; 9 int father[N], num[N];//father用來保存相交的線段的集合,num表示當前線段所在集合有多少條線段 10 point a[N], b[N];//a代表一個線段的起點,b代表終點 11 //初始化 12 void init(int n) 13 { 14 15 for (int i = 1; i <= n; i++) 16 { 17 father[i] = i; 18 num[i] = 1; 19 } 20 } 21 double Min(double a, double b) 22 { 23 return a < b ? a : b; 24 } 25 double Max(double a, double b) 26 { 27 return a > b ? a : b; 28 } 29 //用來判斷點c在線段ab的哪一側,如果返回正值就是逆時針那側,如果是負值就是順時針那側 30 double direction(point a, point b, point c) 31 { 32 point t1, t2; 33 t1.x = c.x - a.x; t1.y = c.y - a.y; 34 t2.x = b.x - a.x; t2.y = b.y - a.y; 35 return (t1.x * t2.y - t1.y * t2.x); 36 } 37 //前提條件已知ac和ab共線了,判斷點c是否在線段ab上,如果是就返回true; 38 bool onSegment(point a, point b, point c) 39 { 40 double minx, miny, maxx, maxy; 41 minx = Min(a.x, b.x); 42 maxx = Max(a.x, b.x); 43 miny = Min(a.y, b.y); 44 maxy = Max(a.y, b.y); 45 return (c.x >= minx && c.x <= maxx && c.y >= miny && c.y <= maxy); 46 } 47 //判斷線段是否相交,線段一是p1p2, 線段二是p3p4,如果相交返回true; 48 bool segment_intersect(point p1, point p2, point p3, point p4) 49 { 50 //判斷p1在線段p3p4的哪一側 51 double d1 = direction(p3, p4, p1); 52 //判斷p2在線段p3p4的哪一側 53 double d2 = direction(p3, p4, p2); 54 //判斷p3在線段p1p2的哪一側 55 double d3 = direction(p1, p2, p3); 56 //判斷p4在線段p1p2的哪一側 57 double d4 = direction(p1, p2, p4); 58 //如果相互跨越 59 if (d1 * d2 < 0 && d3 * d4 < 0) 60 return true; 61 //下面四個是邊界情況,第一個是點p1在線段P3p4上的時候 62 else if (d1 == 0 && onSegment(p3, p4, p1)) 63 return true; 64 else if (d2 == 0 && onSegment(p3, p4, p2)) 65 return true; 66 else if (d3 == 0 && onSegment(p1, p2, p3)) 67 return true; 68 else if (d4 == 0 && onSegment(p1, p2, p4)) 69 return true; 70 return false; 71 } 72 //并查集查找 73 int find(int x) 74 { 75 while (x != father[x]) 76 x = father[x]; 77 return x; 78 } 79 //合并 80 void merge(int a, int b) 81 { 82 int ta = find(a); 83 int tb = find(b); 84 if (ta != tb) 85 { 86 father[ta] = tb; 87 num[tb] += num[ta]; 88 } 89 } 90 int main() 91 { 92 int t, n; 93 scanf("%d", &t); 94 while (t--) 95 { 96 int index = 0; 97 scanf("%d", &n); 98 init(n); 99 char option; 100 for (int i = 0; i < n; i++) 101 { 102 getchar(); 103 scanf("%c", &option); 104 if (option == 'P') 105 { 106 ++index; 107 scanf("%lf %lf %lf %lf", &a[index].x, &a[index].y, &b[index].x, &b[index].y); 108 for (int i = 1; i < index; i++) 109 if (segment_intersect(a[i], b[i], a[index], b[index])) 110 merge(i, index); 111 } 112 else 113 { 114 int k; 115 scanf("%d", &k); 116 printf("%d\n", num[find(k)]); 117 } 118 } 119 if (t) 120 puts(""); 121 } 122 return 0; 123 } View Code

?

轉載于:https://www.cnblogs.com/Howe-Young/p/4360210.html

總結

以上是生活随笔為你收集整理的判断线段相交(hdu1558 Segment set 线段相交+并查集)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: av资源在线看 | 中文字幕免费在线看线人 | 黄色裸体视频 | 一本久久综合亚洲鲁鲁五月天 | 成人午夜在线播放 | 91天堂网 | 亚洲操 | 毛片免 | 欧美一区二区三区在线观看视频 | 91成人在线观看高潮 | 激情综合网五月婷婷 | 国产情侣露脸自拍 | 免费h片在线观看 | 亚洲一区二区在线免费 | 亚洲综合网址 | av在线免费观看网站 | 成人精品一区二区三区电影 | 中文字幕在线国产 | 国产不卡一区二区视频 | 国产精品美女自拍视频 | 国产又黄又猛视频 | 蜜臀av一区二区三区有限公司 | 亚洲精品污 | 尤物视频最新网址 | 中文字幕永久在线观看 | 少妇一级淫片免费放2 | 嫩草研究院在线观看 | 欧美福利精品 | 欧美老肥妇做.爰bbww视频 | 久久久看片| av福利影院 | 国产成人免费视频网站 | 黄色成人毛片 | 热久久国产精品 | 毛片一区二区三区 | 射进来av影视网 | 亚洲欧洲成人在线 | 少妇搡bbbb搡bbb搡打电话 | 国产区精品在线观看 | 日本三不卡 | 成人国产精品免费观看视频 | 国产精品swag | av导航在线 | 偷拍网亚洲 | 欧美一级片在线观看 | 九九热视频在线观看 | 国产白袜脚足j棉袜在线观看 | 亚洲永久无码7777kkk | 老女人性生活视频 | 男人午夜天堂 | 日韩视频播放 | 乱岳 | 成人一区二区视频 | 日本不卡免费在线 | 成人娱乐网 | 欧美精品在线一区二区 | 天堂av影院 | 四虎国产精品成人免费入口 | 欧美成人午夜电影 | 西西人体做爰大胆gogo | 日韩三级黄色 | 91插视频 | 成人免费xxxxx在线视频 | 欧美操女人 | 欧美三级小视频 | 国产精品麻豆果冻传媒在线播放 | www.日韩av.com| 水蜜桃久久 | 国产亚洲精品久久久久久久 | 国产精品夜色一区二区三区 | av首页在线 | 性午夜| 日本免费一级片 | 一级国产黄色片 | 国产精品国产三级国产aⅴ中文 | 99精品久久99久久久久 | 久草精品视频在线观看 | 涩涩视频免费观看 | 亚洲黄色精品视频 | 亚洲成a人v欧美综合天堂麻豆 | 成人精品福利 | 好吊色在线视频 | 伊人一区二区三区四区 | 91精品视频国产 | 新av在线 | 中文字幕在线观看91 | 一区二区三区久久久久 | 亚洲狠狠爱 | 国产v片 | 黄色av网站在线免费观看 | 欧美a免费 | 扒开腿揉捏花蒂h | 99久久综合网| 日韩国产欧美在线视频 | 性生交生活影碟片 | 亚洲精品国产精品国自产在线 | 色悠悠国产 | 成人毛片一级 | 91成人在线免费 |