解题思路:关于计算几何部分详见下面代码的注释,以及挑战p253。这道题可以拿出来做模板的地方on_seg,用于判断一个点是否在直线上。和intersection求交点部分,但是不能处理两条直线平行的情况,需要提前判断两条线是否平行。最后用了floyd算法来进行相连拓展。其实这里证明floyd可行性是一个比较复杂的过程,但是我们可以联想前面求最短路的时候,
dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]),这说明是正则的,最后的结果可以收敛。更简单的说和这次用到的形式一样,所以可以套用。
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
const double eps=1e-10;
int n;
double add(double a,double b)
{
if(abs(a+b)<eps*(abs(a)+abs(b))) return 0;
return a+b;
}
struct node
{
double x,y;
node(){
}
node(double x,double y):x(x),y(y){
}
node operator+(node p)
{
return node(add(x,p.x),add(y,p.y));
}
node operator-(node p)
{
return node(add(x,-p.x),add(y,-p.y));
}
node operator*(double d)
{
return(node(d*x,d*y));
}
double dot(node p)
{
return add(x*p.x,y*p.y);
}
double det(node p)
{
return add(x*p.y,-y*p.x);
}
};
node p[20],q[20];
bool g[40][40];
int on_seg(node p,node q,node r)//这一段处理很不错,判断坐标r在不在线段p-q上
{
if(((p-r).det(q-r))==0 && (p-r).dot(q-r)<=0)
return 1;
return 0;
}
node intersection(node p1,node p2,node q1,node q2)//计算p1-p2和q1-q2直线交点
{
return p1+(p2-p1)*((q2-q1).det(q1-p1)/(q2-q1).det(p2-p1));//这种计算方法挺不错,可以处理斜率不存在的情况!
}
void solve()
{
memset(g,0,sizeof(g));
for(int i=0;i<n;i++)
{
g[i][i]=1;
for(int j=0;j<i;j++)
{
if((p[i]-q[i]).det(p[j]-q[j])==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
{
node tp=intersection(p[i],q[i],p[j],q[j]);
//if(i==3&&j==0) printf("%(%lf %lf) %lf %lf*\n",p[i].x,p[i].y,tp.x,tp.y);
g[i][j]=g[j][i]=on_seg(p[i],q[i],tp)&&on_seg(p[j],q[j],tp);
}
}
}
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()
{
//freopen("t.txt","r",stdin);
int a,b;
while(~scanf("%d",&n)&&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);
}
solve();
while(~scanf("%d%d",&a,&b))
{
if(a==0&&b==0) break;
if(g[a-1][b-1])
printf("CONNECTED\n");
else
printf("NOT CONNECTED\n");
}
}
return 0;
}