hdu - 3952 Fruit Ninja(简单几何)

思路来自于:http://www.cnblogs.com/wuyiqi/archive/2011/11/06/2238530.html

枚举两个多边形的两个点组成的直线,判断能与几个多边形相交

因为最佳的直线肯定可以经过某两个点(可以平移到顶点处),所以暴力枚举两个点就好了

如果有模版的话,写代码就快多了。

代码如下:

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <string>
#include <cmath>
#include <queue>
#include <stack>
#include <vector>
#include <map>

#define LL long long
#define eps 1e-8
#define N 15
#define K 15

using namespace std;

struct Point{
    double x, y;
    Point operator - (const Point &t) const
    {
        Point temp;
        temp.x = x-t.x;
        temp.y = y-t.y;
        return temp;
    }
    Point operator + (const Point &t) const
    {
        Point temp;
        temp.x = x+t.x;
        temp.y = y+t.y;
        return temp;
    }
    bool operator == (const Point &t) const
    {
        return fabs(x-t.x)<eps&&fabs(y-t.y)<eps;
    }
};
struct Figure{
    int cnt;
    Point poi[K];
};
struct Line{
    double a, b, c;
};
Figure fig[N];
Line t_Line(Point a, Point b)//点到直线的转化
{
    Line temp;
    temp.a = a.y-b.y;
    temp.b = b.x-a.x;
    temp.c = a.x*b.y-b.x*a.y;
    return temp;
}
bool Line_Inst(Line l1, Line l2, Point &p)//判断直线相交,并求交点
{
    double a1 = l1.a, b1 = l1.b, c1 = l1.c;
    double a2 = l2.a, b2 = l2.b, c2 = l2.c;
    if(fabs(a1*b2-a2*b1)<eps) return false;
    p.x = (b1*c2-b2*c1)/(a1*b2-a2*b1);
    p.y = (a1*c2-a2*c1)/(a2*b1-a1*b2);
    return true;
}
double cross(Point a, Point b, Point c)//求向量的叉积,判断三点是否共线
{
    return (b.x-c.x)*(a.y-c.y)-(b.y-c.y)*(a.x-c.x);
}
bool dotOnSeg(Point a, Point b, Point c)//判断点是否在线段上
{
    if(a==c||b==c) return true;
    return cross(a,b,c)<eps&&
    (b.x-c.x)*(a.x-c.x)<eps&&
    (b.y-c.y)*(a.y-c.y)<eps;
}
int main ()
{
    int t, n, k, kk = 0;
    scanf("%d", &t);
    while(t--)
    {
        scanf("%d", &n);
        for(int i = 1; i <= n; ++i)
        {
            scanf("%d", &k);
            fig[i].cnt = k;
            for(int j = 1; j <= k; ++j)
                scanf("%lf %lf", &fig[i].poi[j].x, &fig[i].poi[j].y);
        }
        if(n<=2)
        {
            printf("Case %d: %d\n",++kk, n);
            continue;
        }
        int ans = 0;
        Point p;
        for(int i = 1; i <= n; ++i)
            for(int j = i+1; j <= n; ++j)
                for(int k = 1; k <= fig[i].cnt; ++k)
                    for(int l = 1; l <= fig[j].cnt; ++l)
                    {
                        Line l1 = t_Line(fig[i].poi[k], fig[j].poi[l]);//找到经过两个图形的顶点的直线
                        int tt = 2;
                        for(int ii = 1; ii <= n; ++ii)
                        {
                            if(ii==i||ii==j) continue;
                            for(int jj = 1; jj < fig[ii].cnt; ++jj)
                            {
                                Line l2 = t_Line(fig[ii].poi[jj], fig[ii].poi[jj+1]);//图形的两个相邻节点组成一条直线
                                if(Line_Inst(l1,l2,p)&&dotOnSeg(fig[ii].poi[jj], fig[ii].poi[jj+1], p))
                                {//直线相交,并且交点位于线段上,即可证明直线l1穿过线段
                                    ++tt;
                                    break;
                                }
                            }
                        }
                        ans = max(ans, tt);
                    }
        printf("Case %d: %d\n",++kk, ans);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值