ZOJ1010

题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=1010

每次做几何题总能学到新东西,而且永远也学不完,并且学完以后从来没用过尴尬

(向量 a=(x1, y1),向量 b=(x2, y2),向量c=(x3, y3),向量d=(x4,y4))

叉乘和点乘:

叉乘:a × b = x1 * y2 - x2 * y1;

点乘:a * b = x1 * x2 + y1 * y2。

其中叉乘的结果的绝对值是三角形面积的两倍(叉乘的结果是三角形有向面积的两倍),结果等于0,向量共线;大于0,b在a的逆时针方向;小于0,b在a的顺时针方向。

判断边ab与cd相交:


判断点a,b,c有重合的点:

那么就会有(三点共线)并且(两线垂直),就会重合。


计算面积:

A = 0.5 * (p0 × p1 + p1 ×p2 +...+ p(n-1)  × pn) (公式适用于凸多边形和凹多边形,p是点的编号,p0和pn是同一个点,把点坐标当做向量坐标来求叉积)。

#include<iostream>
#include<cstdio>
#include<cmath>
#define eps 1e-8
using namespace std;

double x[1010], y[1010];

double area(int n, double x[], double y[])
{
    int i;
    double ans = 0;
    for (i=1; i<=n; i++)
        ans += x[i-1] * y[i] - y[i-1] * x[i];
    return fabs(ans / 2);
}

double cross(int a, int b, int c)
{
    return (x[b] - x[a]) * (y[c] - y[a]) - (x[c] - x[a]) * (y[b] - y[a]);
}

double dot(int a, int b, int c)
{
    return (x[b] - x[a]) * (x[c] - x[a]) + (y[b] - y[a]) * (y[c] - y[a]);
}

int compare(double d)
{
    if (fabs(d) < eps)
        return 0;
    return d > 0 ? 1 : -1;
}

int between(int a, int b, int c)
{
    return compare(dot(a, b, c));
}

int intersect(int s, int t)
{
    int d1 = compare(cross(s, s+1, t));
    int d2 = compare(cross(s, s+1, t+1));
    int d3 = compare(cross(t, t+1, s));
    int d4 = compare(cross(t, t+1, s+1));
    if (d1 * d2 < 0 && d3 * d4 < 0)
        return 1;

    if (d1 == 0 && between(s, s+1, t) == 0 ||
        d2 == 0 && between(s, s+1, t+1) == 0 ||
        d3 == 0 && between(t, t+1, s) == 0 ||
        d4 == 0 && between(t, t+1, s+1) == 0)
            return 2;
    return 0;
}

int main()
{
    int n;
    int iCase = 0;
    int i, j;
    while (scanf("%d",&n) && n)
    {
        for (i=1; i<=n; i++)
            cin>>x[i]>>y[i];
        x[0] = x[n];
        y[0] = y[n];
        if (iCase)
            cout<<endl;
        printf("Figure %d: ",++iCase);
        int flag = 1;
        if (n < 3)
            flag = 0;
        for (i=n-3; i>=0 && flag; i--)
            for (j=i+2; j<n && flag; j++)
        {
            if (i == 0 && j == n-1)
                break;
            if (intersect(i, j))
                flag = 0;
        }
        if (flag)
            printf("%.2lf\n",area(n, x, y));
        else
            printf("Impossible\n");
    }

    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值