您的位置:首页 > 其它

hdu 1558 Segment set 线段相交+并查集

2014-04-09 20:38 429 查看
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1558

题目大意:有T组测试数据,对每组测试数据,有N行,如果输入的字符为P ,接着输入两个点的横纵坐标,即为一个线段的两个端点,如果字符为P,接着输入一个序号K,输出与第K次输入的线段有交点的线段的总数。题意很明显使用并查集,但是对于线段相交的判断比较麻烦,代码如下:

#include<stdio.h>
#define max(a,b) (a>b?a:b)
#define min(a,b) (a>b?b:a)
int T,n;
struct point{double x,y;};//点的结构体
struct zb{point a,b;}s[1005];//线段的结构体
int f[1005],rank[1005];
void init()//并查集的初始化
{
for(int i=1;i<1005;i++)
{
f[i]=i;rank[i]=1;
}
}
int find(int x)//状态压缩查找
{
if(x==f[x]) return x;
return f[x]=find(f[x]);
}
void merge(int x,int y)//按秩合并
{
int fx=find(x);
int fy=find(y);
if(fx!=fy)
{
if(rank[fx]>rank[fy])
{rank[fx]+=rank[fy];f[fy]=fx;}
else
{rank[fy]+=rank[fx];f[fx]=fy;}
}
}
double ccw(point a,point b,point c)//三角形的有向面积,用来判断
//点c在直线a,b的左边还是右边,大于零左边,小于零右边,等于零直线上
{
double m=(a.x*b.y+b.x*c.y+c.x*a.y-a.x*c.y-b.x*a.y-c.x*b.y);
return m;
}
//判断两个线段是否相交,前面四个条件是使两条线段形成一个包围盒,如果有交点
//肯定在包围盒内,后面两个条件是保证使一条线段的两点不在另外一条线段的一侧
bool judge(point a,point b,point c,point d)
{
if(max(a.x,b.x)>=min(c.x,d.x)&&max(a.y,b.y)>=min(c.y,d.y)&&
max(c.x,d.x)>=min(a.x,b.x)&&max(c.y,d.y)>=min(a.y,b.y)&&
ccw(a,b,c)*ccw(a,b,d)<=0&&ccw(c,d,a)*ccw(c,d,b)<=0)
return true;
return false;
}
int main()
{
char c[2];
scanf("%d",&T);
while(T--)
{
int k=1;
scanf("%d",&n);
init();
while(n--)
{
scanf("%s",c);
if(c[0]=='P')
{
scanf("%lf%lf%lf%lf",&s[k].a.x,&s[k].a.y,&s[k].b.x,&s[k].b.y);
for(int i=1;i<k;i++)
{
if(judge(s[i].a,s[i].b,s[k].a,s[k].b))
merge(i,k);
}
k++;
}
else
{
int f;
scanf("%d",&f);
printf("%d\n",rank[find(f)]);//rank[]的大小就是当前包含的线段数
}
}
if(T) printf("\n");
}
}

这道题最重要的应该是学会了线段相交的模板。。。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: