现在的位置: 首页 > 综合 > 正文

hdu1558–并查集+判断线段相交

2017年07月10日 ⁄ 综合 ⁄ 共 1587字 ⁄ 字号 评论关闭

简单的计算几何题,判断两线段是否相交。将相交的两线段使用并查集归到一类中。查询时输出线段对应集合中元素的个数。

#include<stdio.h>

struct Point{
	double x,y;
};
struct Segment{
	Point s,e;
}node[1010];
int n,parent[1010];
int getAbs(int value)
{
	if(value>=0)return value;
	return -value;
}
int getParent(int a){
	while(parent[a]>0)a=parent[a];
	return a;
}
void Union(int a,int b)
{
	int r1 = getParent(a);
	int r2 = getParent(b);
	if(r1!=r2)
	{
		if(r1<r2)
		{
			parent[r1]+=parent[r2];//合并两个集合时,计算两个集合的元素个数
			parent[r2]=r1;
		}else{
			parent[r2]+=parent[r1];
			parent[r1]=r2;
		}
	}
}
double max(double a,double b)
{
	if(a>=b)return a;
	return b;
}
double min(double a,double b)
{
	if(a>=b)return b;
	return a;
}
/** 
* 计算向量 ps,pe的叉积
*/
double multiply(Point p,Point s,Point e)
{
	return (s.x-p.x)*(e.y-p.y)-(e.x-p.x)*(s.y-p.y);
}
int main()
{
	int t,n,i,j,num,cnt;
	char command;
	scanf("%d",&t);
	while(t--)
	{
		scanf("%d",&n);
		cnt=0;
		//初始时每个元素都是一个集合
		for(i=1;i<=n;i++)parent[i]=-1;
		for(i=1;i<=n;i++)
		{
			getchar();
			scanf("%c",&command);
			if(command=='P'){
				cnt++;
				scanf("%lf%lf%lf%lf",&node[cnt].s.x,&node[cnt].s.y,&node[cnt].e.x,&node[cnt].e.y);
				for(j=1;j<cnt;j++)
				{
					//判断第cnt个线段是否与前面的cnt-1个线段有相交。
					if(max(node[cnt].s.x,node[cnt].e.x)>=min(node[j].s.x,node[j].e.x)
						&& max(node[j].s.x,node[j].e.x)>=min(node[cnt].s.x,node[cnt].e.x)
						&& max(node[cnt].s.y,node[cnt].e.y)>=min(node[j].s.y,node[j].e.y)
						&& max(node[j].s.y,node[j].e.y)>=min(node[cnt].s.y,node[cnt].e.y)
						&& multiply(node[cnt].s,node[j].s,node[j].e)*multiply(node[cnt].e,node[j].s,node[j].e)<=0
						&& multiply(node[j].s,node[cnt].s,node[cnt].e)*multiply(node[j].e,node[cnt].s,node[cnt].e)<=0)
					{
						//有相交就合并集合
						Union(cnt,j);
					}
				}
			}else
			{
				scanf("%d",&num);
				//当parent为负数时,其绝对值就是该集合的元素个数。
				printf("%d\n",getAbs(parent[getParent(num)]));
			}
		}
		if(t!=0)
		{
			printf("\n");
		}
	}
	return 0;
}
【上篇】
【下篇】

抱歉!评论已关闭.