poj 3304 Segments

http://poj.org/problem?id=3304

题意是问是否存在一条直线,使得所有线段在这直线上的投影都有至少一个公共点。

我们假设存在这样的一条直线,在直线公共部分作一垂线,那么垂线必定过所有的线段,所以,我们可以反过来考虑,那么题目就变成求是否存在一直线过所有的线段,然后我们就可以枚举每一个点,具体方法:先取两不同点,然后在余下的点进行枚举,用叉乘来判断是否相交,叉乘判断方法如下:

设线段端点为从 A(x1, y1)到 B(x2, y2), 线外一点 P(x0,y0),
判断该点位于有向线 A→B 的那一侧。 
a = ( x2-x1, y2-y1) 
b = (x0-x1, y0-y1) 
a x b = | a | | b | sinφ (φ为两向量的夹角) 
| a | | b |  ≠ 0 时,  a x b  决定点 P的位置 
所以  a x b  的 z 方向大小决定 P位置 
(x2-x1)(y0-y1) – (y2-y1)(x0-x1)  >  0   左侧 
(x2-x1)(y0-y1) – (y2-y1)(x0-x1)  <  0   右侧 
(x2-x1)(y0-y1) – (y2-y1)(x0-x1)  =  0   线段上 


AC代码:

#include<iostream>
#include<vector>
#include<map>
#include<stack>
#include<algorithm>
#include<queue>
#include<list>
#include<set>
#include<string.h>
#include<stdlib.h>
#include<math.h>
#include<stdio.h>
#include<ctype.h>
#include<iomanip>

using namespace std;

#define LL long long
#define pi acos(-1)
#define N 6000
#define INF 9999999999

struct node
{
    double x,y;
}p[210];

double cal(node a,node b,node c)
{
    return (a.x-b.x)*(b.y-c.y)-(b.x-c.x)*(a.y-b.y);
}


int main()
{
    //freopen("a.txt","r",stdin);
    int t;
    int n;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
        int i,j,k;
        for(i=1;i<=2*n;i+=2)
            scanf("%lf%lf%lf%lf",&p[i].x,&p[i].y,&p[i+1].x,&p[i+1].y);
            int flag=0;
        for(i=1;i<=2*n;i++)
            for(j=1;j<=2*n;j++)
            {
                node a=p[i],b=p[j];
                if(a.x==b.x && a.y==b.y)
                    continue;
                for(k=1;k<=2*n;k+=2)
                {
                    if(p[k].x==a.x&&p[k].y==a.y && p[k+1].x==b.x&&p[k+1].y==b.y)
                        continue;
                    if(cal(p[k],a,b)*cal(p[k+1],a,b)>1e-8)
                    {
                        break;
                    }
                }
                if(k>2*n)
                {flag=1;break;}
            }
        if(flag)
        printf("Yes!\n");
        else
        printf("No!\n");
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值