POJ 3304 Segments

原题地址 点击打开链接

题意: 给出n条线段两个端点的坐标,问所有线段投影到一条直线上,如果这些所有投影至少相交于一个点就输出Yes!,否则输出No!。
解题思路:如果有存在这样的直线,过投影相交区域作直线的垂线,该垂线必定与每条线段相交,问题转化为问是否存在一条直线和所有线段相交
若存在一条直线与所有线段相机相交,此时该直线必定经过这些线段的某两个端点,所以枚举任意两个端点即可。

直线与线段相交判断: 如下图, 设直线为AB, 线段为PQ, 利用叉积性质, 线段两端在直线的两旁, 即向量(BP x BA)* (BA x BQ) <=0

代码

#include <cstdio>
#include <cmath>
#include <iostream>
#include <stdlib.h>
using namespace std;
#define esp 1e-8
struct point
{
	double x1, y1, x2, y2;
}p[105];

int n, flag;
double distance(double x1,double y1,double x2,double y2){
    return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
}

double corss(double x1,double y1,double x2,double y2,double x,double y){
    return (x2-x1)*(y-y1)-(x-x1)*(y2-y1);
}

bool judge(double x1,double y1,double x2,double y2){
    int i;
    if(distance(x1,y1,x2,y2)<esp) return 0; //判断重复点
    for(i=0;i<n;i++){
        if(corss(x1,y1,x2,y2,p[i].x1,p[i].y1)*
            corss(x1,y1,x2,y2,p[i].x2, p[i].y2)>esp)  //判断相交
            return 0;
    }
    return 1;
}

int main()
{
	int t, i, j;
	cin >> t;
	while(t--)
	{
		cin >> n;
		for(i=0; i<n;i++)
		{
			cin >> p[i].x1 >> p[i].y1 >> p[i].x2 >> p[i].y2;
		}
		if(n==1 || n==2)
		{
			printf("Yes!\n");
			continue;
		}
		flag = 0;
		for(i=0; i<n;i++)
		{
			for(j=i+1; j<n; j++)
			{ //枚举
				if(judge(p[i].x1, p[i].y1, p[j].x1, p[j].y1) && !flag) flag = 1;
				if(judge(p[i].x2, p[i].y2, p[j].x1, p[j].y1)&& !flag) flag = 1;
				if(judge(p[i].x1, p[i].y1, p[j].x2, p[j].y2)&& !flag) flag = 1;
				if(judge(p[i].x2, p[i].y2, p[j].x2, p[j].y2)&& !flag) flag = 1;
			}
		}

		if(flag) printf("Yes!\n");
		else printf("No!\n");
	}
	return 0;
	system("pause");
}



COD

posted @ 2014-09-09 11:00  豪气干云  阅读(141)  评论(0编辑  收藏  举报