HDU1558 - Segment set 并查集 + 判断线段相交

HDU1558 - Segment set: http://acm.hdu.edu.cn/showproblem.php?pid=1558

题目大意: 输入一些线段的端点坐标,若两线段相交,则把他们合并成一个集合,输入数据里会有k,问和k线段相交的线段的数目(包括自己)

思路: 每次输入一条线段,都从头扫描一次. 找出之前输入的线段里面,所有和其相交的线段,并且合并(合并用的是线段的ID). 就是: 并查集 + 判断线段相交

代码:

#include <iostream>
#include <cstring>
#define maxn 1005
using namespace std;
int father[maxn];
struct point{
	double x1,y1,x2,y2;
}p[maxn];//结构体储存线段的两个端点坐标
bool judge(point x,point y)//利用 叉积 判断线段相交
{
	double m=(y.x2-y.x1)*(x.y1-y.y1)-(y.y2-y.y1)*(x.x1-y.x1);
	double n=(y.x2-y.x1)*(x.y2-y.y1)-(y.y2-y.y1)*(x.x2-y.x1);
	if(m*n<=0)return true;
	return false;
}
int find(int x)
{
	return x == father[x] ? x : father[x] = find(father[x]);
}
void join(int x,int y)
{
	x=find(x),y=find(y);
	if(x!=y)
		father[x]=y;
}
int main()
{
	int t,n,k;
	int count,flag;
	char s;
	cin>>t;
	while(t--)
	{
		for(int i=0;i<maxn;i++)father[i]=i;
		cin>>n;
		flag=1;//记录的是线段的数目
		for(int i=0;i<n;i++)
		{
			cin>>s;
			if(s=='P')
			{
				cin>>p[flag].x1>>p[flag].y1>>p[flag].x2>>p[flag].y2;
				for(int j=1;j<flag;j++)//每次输入都从头开始扫描之前输入了的线段,判断当前线段是否会和他们相交
				{
					if(judge(p[flag],p[j])&&judge(p[j],p[flag]))//判断两线段是否相交
						join(flag,j);//相交则将他们合并
				}
				flag++;
			}else{
				count=0;
				cin>>k;
				int x=find(k);
				for(int j=0;j<flag;j++)//计算与k线段是同一集合的线段数目
					if(find(j)==x)count++;
				cout<<count<<endl;
			}
		}
		if(t)cout<<endl;
	}
	return 0;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-08-05 06:41:46

HDU1558 - Segment set 并查集 + 判断线段相交的相关文章

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

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1558 解题报告:首先如果两条线段有交点的话,这两条线段在一个集合内,如果a跟b在一个集合内,b跟c在一个集合内,那么a跟c在一个集合内.在一个平面上,有两种操作: P:在这个平面上添加一条线段 Q k:询问添加的第k条线段所在的那个集合有多少条线段 用并查集,然后就是要判断一下线段有没有交点.还有就是题目要求两个test之间要有空行,为此我还PE了一次. 1 #include<cstdio> 2

hdu 1558 Segment set(并查集+判断线段是否相交)

代码: #include<cstdio> #include<cstring> #include<algorithm> using namespace std; int father[1005]; int son_cnt[1005]; char s[5]; //int cnt; struct point { double x,y; }; point a[1005],b[1005]; int find_father(int x) { int r=x; while(fathe

URAL - 1966 - Cycling Roads(并查集 + 判线段相交)

题意:n 个点,m 条边(1 ≤ m < n ≤ 200),问所有点是否连通(两条边相交,则该 4 点连通). 题目链接:http://acm.timus.ru/problem.aspx?space=1&num=1966 -->>对于每条边,边上的两端点并入集合,枚举边与边,判断他们是否相交,是的话各点并入集合,最后看集合内元素的个数是否为n.. #include <cstdio> #include <cmath> const int MAXN = 200

nyoj 单词拼接(并查集判断连通性+欧拉路径)

这题还是比较难的. 首先建图方面,如果单纯的把单词作为点,能拼接的关系作为边,那么就是哈密顿图(每个点仅能走一次),难度比较大. 换一种思路,就是把每个单词看成一条有向边,由该单词的首字母指向尾字母. 那么这题便是欧拉图的问题了. 本质上采用的还是搜索,但是为了快速得到字典序最小的欧拉路径,首先要对单词集进行排序. 排完序后,用边集数组存图:再通过计算各点的出度与入度,同时判断基图(不考虑边的方向的图)的连通性,判断是否存在欧拉回路或欧拉通路. 如果存在欧拉回路,那么就从0开始搜索: 如果存在欧

Codeforces Round #423 (Div. 2) C 思维,并查集 或 线段树 D 树构造,水

Codeforces Round #423 (Div. 2, rated, based on VK Cup Finals) C. String Reconstruction   思维,并查集 或 线段树 题意:一个字符串被删除了,但给出 n条信息,要还原出可能的字典序最小的字符串.信息有:字符串ti,ki个位置xi,表明原本的字符串在xi位置是以字符串ti开头的. tags:惨遭 fst,一开始把所有字符串都存下来,排序做的,结果爆内存了.. 方法1: 考虑并查集,对于字符串 ti,在位置xi,

hdu 5424 回溯+并查集判断连通性

题意:给定一个n个点n条边的无向图,判断是否存在哈密顿路径. 思路:先用并查集判断图是否连通,然后从度数最小的点开始回溯,看是否能找到一条哈密顿路径. 1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 #include <set> 5 using namespace std; 6 7 const int INF = 999999; 8 const int N = 1001; 9

HDOJ Ice_cream&#39;s world I 2120【并查集判断成环】

Ice_cream's world I Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 848    Accepted Submission(s): 494 Problem Description ice_cream's world is a rich country, it has many fertile lands. Today,

用并查集判断一个无向图中是否存在环

并查集是一种树型的数据结构,用于处理一些不相交集合(Disjoint Sets)的合并及查询问题.常常在使用中以森林来表示.集就是让每个元素构成一个单元素的集合,也就是按一定顺序将属于同一组的元素所在的集合合并. Find:确定元素属于哪一个子集.它可以被用来确定两个元素是否属于同一子集合. Union:将两个子集合并成同一个集合. 其实判断一个图是否存在环已经有相应的算法,此文用并查集来判断一个图是否有环. 我们可以用一个一维数组parent[] 来记录子集合. 看下面这个图: 0 |   \

并查集(判断一个图有几个连通块)

import java.util.Scanner; // 并查集 判断一个图中有几个联通块 public class UnionFind { private int[] father;// private int count;// 分量数量 public UnionFind(int N){ count=N; father=new int[N]; for(int i=0;i<N;i++){ father[i]=i; } } public int count() { return count; }