链接:http://poj.org/problem?id=1127
题意:给定m对木棍,判断是否相连,如果两者有公共点就可以认为是相连的。通过相连的木棍连在一起的两个木棍也可以认为是相连的。
所用到的知识:
计算几何通常采用向量的形式来描述线段。
这里运用 * 来表示向量的点积, ^ 来表示向量的叉积。
求判断点q是否在线段p2-p1上,首先判断点q是否在这条直线上,(p1-q)^(p2-q) = 0 即在直线上,在判断是否在线段内,(p1-q)*(p2-q) <= 0 即在线段内。
求两条直线的交点:
将直线p2-p1上的点表示为p1+t(p2-p1),交点又在直线q1-q2上。
故有: (q2-q1)^(p1+t(p2-p1)-q1) = 0
所以t = p1+((q2-q1)^(q1-p1))/((q2-q1)^(p2-p1)) * (p2-p1)
如果相连,1)可能重合。2)可能直接是相交的。
由于最后一个描述,还需要运用floyd来判断一下,任意两点之间是否相连。
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
#define M 20
#define EPS 1e-10
//精度不要调太高。。 1e-15 wa
struct P
{
double x,y;
P(){}
P(double x,double y):x(x),y(y){};
P operator + (P p)
{
return P(x+p.x,y+p.y);
}
P operator * (double d)
{
return P(x*d,y*d);
}
double operator * (P p)//点积
{
return x*p.x + y*p.y;
}
double operator ^ (P p) //叉积
{
return x*p.y - y*p.x;
}
P operator - (P p)
{
return P(x-p.x,y-p.y);
}
};
P p[M],q[M];
bool g[M][M];
int n;
bool on_seg(P p1,P p2,P p)
{
if(fabs((p1-p)^(p2-p)) < EPS && (p1-p)*(p2-p) < EPS) return true; //在直线上,并且在线段中
return false;
}
P intersection (P p1,P p2,P q1,P q2) //求直线交点
{
double x = (q2-q1)^(q1-p1);
double y = (q2-q1)^(p2-p1);
return p1 + (p2-p1) * (x/y);
}
void slove()
{
for(int i = 0;i < n;i++)
for(int j = 0;j < n;j++) g[i][j] = false;
for(int i = 0;i < n;i++)
{
g[i][i] = true;
for(int j = 0;j < i;j++)
{
//printf("debug -- p[i].x = %f p[i].y = %f\n",p[i].x,p[i].y);
//printf("debug -- det = %f\n",(p[i]-q[i]).det(p[j]-q[j]));
if(fabs((p[i]-q[i])^(p[j]-q[j])) < EPS) //平行或重合 叉积为0
{
g[i][j] = g[j][i] = on_seg(p[i],q[i],p[j]) || on_seg(p[i],q[i],q[j]) || on_seg(p[j],q[j],p[i]) || on_seg(p[j],q[j],q[i]); //重合,即有公共点
}
else //不平行
{
P a = intersection(p[i],q[i],p[j],q[j]); // 求两直线交点
if(on_seg(p[i],q[i],a) && on_seg(p[j],q[j],a)) //判断交点在线段上
g[i][j] = g[j][i] = true;
}
}
}
//floyd 判断两点之间是否相连
for(int k = 0;k < n;k++)
{
for(int i = 0;i < n;i++)
{
for(int j = 0;j < n;j++)
g[i][j] |= (g[i][k] && g[k][j]);
}
}
}
int main()
{
while(scanf("%d",&n) == 1 && n)
{
for(int i = 0;i < n;i++)
{
scanf("%lf %lf %lf %lf",&p[i].x,&p[i].y,&q[i].x,&q[i].y);
}
slove();
int a,b;
while(scanf("%d %d",&a,&b) == 2)
{
if(a == 0 && b == 0) break;
if(g[a-1][b-1]) printf("CONNECTED\n");
else printf("NOT CONNECTED\n");
}
}
return 0;
}
本文介绍了一种利用计算几何和Floyd算法解决木棍连接问题的方法。通过向量的点积和叉积来判断点是否位于线段上,以及两条线是否相交或重叠。最后使用Floyd算法确保任意两点间是否存在连接路径。
2336

被折叠的 条评论
为什么被折叠?



