HDU 1558 Segment set( 判断线段相交 + 并查集 )
**链接:****传送门 **
题意:输入一个数 n 代表有 n 组操作,P 是在平面内加入一条线段,Q x 是查询第 x 条线段所在相交集合的线段个数
- 例如:下图 5 与 1、2 相交,1 与 3 相交,2 与 4 相交,所以这个相交集合的线段为 1、2、3、4、5,所以 Q 5 答案为 5

思路:
可以使用并查积来描述“相交集合”,如果两个线段相交,就 unite 这两个线段所在集合,需要注意的是,在进行 unite 的时候,需要对两个集合中所有元素进行处理
如何查询每个集合中线段的个数?题目给的数据量较小,可以直接扫描整个 par[] 数组来记录个数
balabala:下面两种做法再次体现了知识面的决定性作用TAT!方法1——46 Ms AC ,方法2——156 Ms AC!接近4倍的时间!
方法1:加一个数组维护集合中线段的个数,这个想法来源于这一道题 ---> 戳这里!
/*************************************************************************
> File Name: hdu1558t2.cpp
> Author: WArobot
> Blog: http://www.cnblogs.com/WArobot/
> Created Time: 2017年05月08日 星期一 19时38分36秒
************************************************************************/
#include<bits/stdc++.h>
using namespace std;
#define eps 1e-10
const int maxn = 1010;
struct point{ double x,y; };
struct V{ point s,e; };
int par[maxn] , num[maxn];
// 线段相交部分
bool inter(point a,point b,point c,point d){
if( min(a.x,b.x) > max(c.x,d.x) ||
min(a.y,b.y) > max(c.y,d.y) ||
min(c.x,d.x) > max(a.x,b.x) ||
min(c.y,d.y) > max(a.y,b.y)
)return 0;
double h,i,j,k;
h = (b.x-a.x)*(c.y-a.y) - (b.y-a.y)*(c.x-a.x);
i = (b.x-a.x)*(d.y-a.y) - (b.y-a.y)*(d.x-a.x);
j = (d.x-c.x)*(a.y-c.y) - (d.y-c.y)*(a.x-c.x);
k = (d.x-c.x)*(b.y-c.y) - (d.y-c.y)*(b.x-c.x);
return h*i<=eps && j*k<=eps;
}
// 并查集部分
void init(){
for(int i=0;i<maxn;i++){
par[i] = i;
num[i] = 1;
}
}
int find(int x){
if(par[x] == x) return x;
else return par[x] = find(par[x]);
}
void unite(int x,int y){
x = find(x);
y = find(y);
if(x==y) return;
else{
par[y] = x;
num[x] += num[y]; // 在合并的同时维护集合数目
}
}
void solve(int k,int x){
int fx = find(x);
unite( k , x );
/*for(int i = 0 ; i < k ; i++){
if( par[i] == fx ) par[i] = k;
}*/
}
int main(){
int T , N , x , k , kase = 0;;
string op;
V v[maxn];
scanf("%d",&T);
while(T--){
if( kase > 0 ) printf("\n");
kase++;
init(); // 初始化并查集
scanf("%d",&N);
k = 0;
while(N--){
cin>>op;
if( op == "P" ){
scanf("%lf%lf%lf%lf", &v[k].s.x , &v[k].s.y , &v[k].e.x , &v[k].e.y );
for(int i = 0 ; i < k ; i++){
if( inter(v[k].s,v[k].e,v[i].s,v[i].e) )
solve( k , i );
}
k++;
}
else{
scanf("%d",&x); x -= 1;
/*int cnt = 0;
for(int i = 0 ; i <= k ; i++){
if( par[i] == par[x] ) cnt++;
}
printf("%d\n",cnt);*/
printf("%d\n", num[ find(x) ] );
}
}
/*for(int i = 0 ; i < k ; i++){
printf("i = %d , par[i] = %d\n",i,par[i]);
}*/
}
return 0;
}
方法2:非常非常蠢的写法
/*************************************************************************
> File Name: hdu1558.cpp
> Author: WArobot
> Blog: http://www.cnblogs.com/WArobot/
> Created Time: 2017年05月08日 星期一 00时00分36秒
************************************************************************/
#include<bits/stdc++.h>
using namespace std;
#define eps 1e-10
const int maxn = 1010;
struct point{ double x,y; };
struct V{ point s,e; };
int par[maxn];
// 线段相交部分
bool inter(point a,point b,point c,point d){
if( min(a.x,b.x) > max(c.x,d.x) ||
min(a.y,b.y) > max(c.y,d.y) ||
min(c.x,d.x) > max(a.x,b.x) ||
min(c.y,d.y) > max(a.y,b.y)
)return 0;
double h,i,j,k;
h = (b.x-a.x)*(c.y-a.y) - (b.y-a.y)*(c.x-a.x);
i = (b.x-a.x)*(d.y-a.y) - (b.y-a.y)*(d.x-a.x);
j = (d.x-c.x)*(a.y-c.y) - (d.y-c.y)*(a.x-c.x);
k = (d.x-c.x)*(b.y-c.y) - (d.y-c.y)*(b.x-c.x);
return h*i<=eps && j*k<=eps;
}
// 并查集部分
void init(){
for(int i=0;i<maxn;i++){
par[i] = i;
}
}
int find(int x){
if(par[x] == x) return x;
else return par[x] = find(par[x]);
}
void unite(int x,int y){
x = find(x);
y = find(y);
if(x==y) return;
else par[y] = x;
}
void solve(int k,int x){
int fx = find(x); // 先找到 x 的祖先再合并 x,否则合并之后就无法处理原本 x 所在集合的所有元素了
unite( k , x );
for(int i = 0 ; i < k ; i++){
if( par[i] == fx ) par[i] = k;
}
}
int main(){
int T , N , x , k , kase = 0;;
string op;
V v[maxn];
scanf("%d",&T);
while(T--){
if( kase > 0 ) printf("\n");
kase++;
init(); // 初始化并查集
scanf("%d",&N);
k = 0;
while(N--){
cin>>op;
if( op == "P" ){
scanf("%lf%lf%lf%lf", &v[k].s.x , &v[k].s.y , &v[k].e.x , &v[k].e.y );
for(int i = 0 ; i < k ; i++){
if( inter(v[k].s,v[k].e,v[i].s,v[i].e) )
solve( k , i );
}
k++;
}
else{
scanf("%d",&x); x -= 1;
int cnt = 0;
for(int i = 0 ; i <= k ; i++){
if( par[i] == par[x] ) cnt++;
}
printf("%d\n",cnt);
}
}
/*for(int i = 0 ; i < k ; i++){
printf("i = %d , par[i] = %d\n",i,par[i]);
}*/
}
return 0;
}
HDU 1558 Segment set( 判断线段相交 + 并查集 )的更多相关文章
- poj 1127:Jack Straws(判断两线段相交 + 并查集)
Jack Straws Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 2911 Accepted: 1322 Descr ...
- hdu 1558 线段相交+并查集
题意:要求相交的线段都要塞进同一个集合里 sol:并查集+判断线段相交即可.n很小所以n^2就可以水过 #include <iostream> #include <cmath> ...
- 判断线段相交(hdu1558 Segment set 线段相交+并查集)
先说一下题目大意:给定一些线段,这些线段顺序编号,这时候如果两条线段相交,则把他们加入到一个集合中,问给定一个线段序号,求在此集合中有多少条线段. 这个题的难度在于怎么判断线段相交,判断玩相交之后就是 ...
- TTTTTTTTTTTTTT poj 1127 Jack Straws 线段相交+并查集
题意: 有n个木棍,给出木棍的两个端点的x,y坐标,判断其中某两个线段是否连通(可通过其他线段连通) #include <iostream> #include <cstdio> ...
- hdu 1558 (线段相交+并查集) Segment set
题目:http://acm.hdu.edu.cn/showproblem.php?pid=1558 题意是在坐标系中,当输入P(注意是大写,我当开始就wa成了小写)的时候输入一条线段的起点坐标和终点坐 ...
- hdu 1558 线段相交+并查集路径压缩
Segment set Time Limit: 3000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total ...
- poj 1127 -- Jack Straws(计算几何判断两线段相交 + 并查集)
Jack Straws In the game of Jack Straws, a number of plastic or wooden "straws" are dumped ...
- [poj 1127]Jack Straws[线段相交][并查集]
题意: 给出一系列线段,判断某两个线段是否连通. 思路: 根据线段相交情况建立并查集, 在同一并查集中则连通. (第一反应是强连通分量...实际上只要判断共存即可, 具体的方向啊是没有关系的..) 并 ...
- poj1127 Jack Straws(线段相交+并查集)
转载请注明出处: http://www.cnblogs.com/fraud/ ——by fraud Jack Straws Time Limit: 1000MS Memory L ...
随机推荐
- Javascript中的原型链,__proto__和prototype等问题总结
1.js中除了原始数据类型 都是对象. 包括函数也是对象,可能类似于C++函数对象把 应该是通过解释器 进行()操作符重载或其他操作, 用的时候把它当函数用就行 但是实际上本质是一个对象 原型也是一个 ...
- springboot实现mongodb上传下载
1.上传: private static Logger log = LoggerFactory.getLogger(MongoDbFSUtil.class); private static final ...
- Zookeeper分布式锁解决方案具体代码
定义一个公共资源订单生成类: package com.itmayiedu.lock; import java.text.SimpleDateFormat; import java.util.Date; ...
- SSM整合(spring,spirngmvc,mybatis)
整合思路 准备环境:导入jar包(spring mybatis dbcp连接池 mysql驱动包 log4j) 工程结构: --------------------------- 1. 整合 ...
- POJ 4786 Fibonacci Tree
Fibonacci Tree Time Limit: 2000ms Memory Limit: 32768KB This problem will be judged on HDU. Original ...
- 工具-VS常用快捷键
项目管理: Ctrl+Shift+N: 新建项目 Ctrl+Shift+O: 打开项目 Ctrl+Shift+S: 全部保存 Shift+Alt+C: 新建类 Ctrl+Shift+A: 新建项 Sh ...
- HDU 4686
再不能直视这道题,换INT64就过了....... 同样可以使用矩阵的方法.构造1*5的 D[N],a[n],b[n],a[n]*b[n],1 接着你应该就会了. #include <iostr ...
- Java&Xml教程(十一)JAXB实现XML与Java对象转换
JAXB是Java Architecture for XML Binding的缩写,用于在Java类与XML之间建立映射,可以帮助开发人员非常方便的將XML和Java对象进行相互转换. 本文以一个简单 ...
- 去哪网实习总结:如何配置数据库连接(JavaWeb)
本来是以做数据挖掘的目的进去哪网的,结构却成了系统开发.. . 只是还是比較认真的做了三个月,老师非常认同我的工作态度和成果. .. 实习立即就要结束了.总结一下几点之前没有注意过的变成习惯和问题,分 ...
- Java中使用多线程、curl及代理IP模拟post提交和get訪问
Java中使用多线程.curl及代理IP模拟post提交和get訪问 菜鸟,多线程好玩就写着玩.大神能够路过不吝赐教.小弟在这受教.谢谢! 很多其它分享请关注微信公众号:lvxing1788 ~~~~ ...