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 ...
随机推荐
- HDU 3306
先转一些 http://www.cnblogs.com/frog112111/archive/2013/05/19/3087648.html Fibonacci数列:F(0)=1 , F(1)=1 ...
- [Performance] Optimize Paint and Composite for the website
"Paint" is one of the most preference killer, it can easily cost more than 60fps, and once ...
- 关于心理的二十五种倾向(查理·芒格)-2
5)避免不一致倾向避免不一致倾向实际上就是人天生就害怕改变.相同是由于人类大脑的生理机制决定的.由于这样的倾向能够带来节省运算空间和能量的优点.这样的抗改变模式的形成,可能的原因例如以下:A) 迅速作 ...
- 一个关于 UIPickerView 的 bug
首先,我下描写叙述一下bug的发生情况: 在使用UIPickerView实现选择城市的时候.出现这样一个Bug 1.在iOS 6的系统上 2.Picker的数据上省份一栏选择了"香港&quo ...
- MySQL官方文档
http://dev.mysql.com/doc/refman/5.7/en/index.html 没有比这更好的MySQL文档了,省的去买书了
- Android 零基础学习之路
第一阶段:Java面向对象编程 1.Java基本数据类型与表达式,分支循环. 2.String和StringBuffer的使用.正則表達式. 3.面向对象的抽象.封装,继承,多态.类与对象.对象初始化 ...
- android:QQ多种側滑菜单的实现
在这篇文章中写了 自己定义HorizontalScrollView实现qq側滑菜单 然而这个菜单效果仅仅是普通的側拉效果 我们还能够实现抽屉式側滑菜单 就像这样 第一种效果 另外一种效果 第三种效果 ...
- centos 下 KVM虚拟机的创建、管理与迁移
kvm虚拟机管理 一.环境 role hostname ip OS kvm_server target 192.168.32.40 ...
- 2015.04.21,外语,读书笔记-《Word Power Made Easy》 11 “如何辱骂敌人” SESSION 31
1.no reverence iconoclast([ai'kɔnәklæst] n. 毁坏宗教神像的人, 提倡打破旧习的人)藐视传统.在青年的反叛期很容易出现iconoclasm([ai'kɔnә ...
- 两个NSMutableDictionary合并成一个NSMutableDictionary
解决方案: NSMutableDictionary *targetMutableDictionary = [mutableDictionary1 copy]; [targetMutableDictio ...