poj 4048 计算几何(线段相交)金华邀请赛 E题

题意说是有个人在一个点o上,然后他拿了一个巨强的诸葛连弩,可以射穿任何东西,现在给你许多城墙(就是线段了),问你他朝那个方向射击会射穿最多的城墙,只要接触城墙就算是射穿了。
分析:计算几何,思路就是离散加枚举。枚举每点到o的射线,我们可在射线的无穷远处选一个点tp和o组成一个线段l。然后记录有多少条线段于l相交,取最大值。

#include <iostream>
#include <cstdio>
#include <cstring>
#define maxn 1600
#define infv 1e6
#define eps 1e-7
using namespace std;
struct node
{
    double x,y;
}b[maxn],e[maxn],stand,inf;
int vb[maxn],ve[maxn];
int crossproduct(node base,node a,node b)//向量base->a与base->b的叉乘
{
    double temp = (a.x - base.x) * (b.y -base.y) - (b.x - base.x) * (a.y - base.y);
    if(temp <= -eps) return -1;
    if(temp >= eps) return 1;
    else return 0;
}


bool intersect(node a ,node b, node c, node d)
{
     //判断线段ab和线段cd相不相交
    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) &&
       crossproduct(a,b,c) * crossproduct(a,d,b) >= 0 &&//大于等于0 //直线ab是否和cd相交
       crossproduct(c,a,d) * crossproduct(c,d,b) >= 0    //直线cd是否和ab相交
      )    
      return true;
      return false;
}


int cases, n,ans,ret,alr;
bool judge(node a, node b, node c)
{//枚举射线,因为intersection这个函数是判断线段和线段相交的
    if(a.x == stand.x){//找无穷大的那个射线点
        inf.x = stand.x;
        if(stand.y > a.y)
            inf.y = -infv;
        else
            inf.y = infv;
    }
    else 
    {
        if(stand.x > a.x)
            inf.x = -infv;
        else
            inf.x = infv;
        inf.y = (a.y - stand.y) * (inf.x - stand.x) * 1.0 / (a.x - stand.x) + stand.y;
    }
    if( intersect(stand,inf,b,c) )  
    return true;
    return false;
}
int main()
{
    scanf("%d",&cases);
    while(cases --){
        scanf("%d",&n);
        for(int i = 0; i < n; i ++){
            scanf("%lf%lf%lf%lf",&b[i].x , & b[i].y , &e[i].x, & e[i].y);
        }
        scanf("%lf%lf",&stand.x, &stand.y);
        memset(vb,0,sizeof(vb));    
        ret = 0;
        memset(ve,0,sizeof(ve));    
        alr = 0;
        for(int i = 0; i < n; i ++)
        {
            if(b[i].x == stand.x && b[i].y == stand.y)
            {//判断是否和线段一个端点重合
                vb[i] ++;
                alr ++;
            }
            if(e[i].x == stand.x && e[i].y == stand.y)
            {//判断是否和线段另一个端点重合
                ve[i] ++;
                alr ++;
            }
        }
        for(int i =  0; i < n; i ++)
        {
            if(!vb[i])
            {
                ans = 0;
                for(int j = 0; j < n; j ++)
                {
                  if( judge(b[i], b[j], e[j]) )
                        ans ++;
                }
                if(ans > ret) ret = ans;
                //   cout << "s " << ans << endl;
            }
            if(!ve[i])
            {
                ans = 0;
                for(int j = 0; j < n; j ++)
                {
                    if(judge( e[i], b[j], e[j]) )  
                     ans ++;
                }
                if(ans > ret) ret = ans;
               //   cout << "e " << ans << endl;
            }
        }
        cout << ret + alr << endl;
     }
    return 0;
}


你可能感兴趣的:(poj 4048 计算几何(线段相交)金华邀请赛 E题)