POJ-1931 Biometrics

题目链接:http://poj.org/problem?id=1931

判断两个多边形是否相似
多边形相似充要条件:多边形A的任何两点之间长度,与多边形B对应的两个点
长度比值都相等注意一下顺时针和逆时针,还有数值的范围*/

#include <math.h>
#include <stdio.h>
#define eps 1e-6
#define sqr(x) ((x) * (x))
#define same(a, b) (fabs((a) - (b)) < eps)
#define dis2(a, b) (sqrt(sqr(a.x - b.x) + sqr(a.y - b.y)))

struct point
{
    double x, y;
    point operator-(point &b)
    {
        point c;
        c.x = x - b.x;
        c.y = y - b.y;
        return c;
    }
};
double dot(point a, point b)
{
    return a.x * b.x + a.y * b.y;
}
double cross(point a, point b)
{
    return a.x * b.y - a.y * b.x;
}
double get_anlge(point p1, point p2, point p3)
{
    //不需要求反余弦,点击相当,反余弦相等,避免使用反三角函数
    return dot(p1 - p2, p3 - p2) / dis2(p1, p2) / dis2(p2, p3);
}
int get_dir(point p1, point p2, point p3)
{
    //根据三点得到转向
    double t1 = cross(p2 - p1, p3 - p2);
    if(fabs(t1) < eps) return 1;
    if(t1 < 0) return 2;
    else return 3;
}
int slove(double ang1[], double ang2[], double len1[], double len2[], int dir1[], int dir2[], int n)
{
    /*由于题目已经告诉了对应点的匹配顺序,所以只需要从
    0,开始匹配,如果没有告诉对应的匹配顺序,就还有枚举
    匹配对应边*/
    int s, t, k;
    s = 0;
    t = 0;
    for(k = 0; k < n; k++)
    {
        if(!same(ang1[s], ang2[t]) || !same(len1[s], len2[t]) || dir1[s] != dir2[t]) break;
        s++;
        t++;
        s %= n;
        t %= n;
    }
    if(k == n) return 1;
    return 0;
}

double polygonArea(point p[], int n)
{
    //已知多边形各顶点的坐标,求其面积
    double area = 0.0;
    for(int i = 1; i <= n; i++)
        area += (p[i - 1].x * p[i % n].y - p[i % n].x * p[i - 1].y);
    return area;
}

int main()
{
    int n, similar;
    point p1[20], p2[20];
    double max1, max2;
    double ang1[20], ang2[20], len1[20], len2[20];
    int dir1[20], dir2[20];
    while(scanf("%d", &n) && n)
    {
        for(int i = 0; i < n; i++)
        {
            scanf("%lf%lf", &p1[i].x, &p1[i].y);
        }
        for(int i = 0; i < n; i++)
        {
            scanf("%lf%lf", &p2[i].x, &p2[i].y);
        }
        ang1[0] = get_anlge(p1[n - 1], p1[0], p1[1]);
        ang2[0] = get_anlge(p2[n - 1], p2[0], p2[1]);
        dir1[0] = get_dir(p1[n - 1], p1[0], p1[1]);
        dir2[0] = get_dir(p2[n - 1], p2[0], p2[1]);
        for(int i = 1; i < n; i++)
        {
            ang1[i] = get_anlge(p1[i - 1], p1[i], p1[(i + 1) % n]);
            ang2[i] = get_anlge(p2[i - 1], p2[i], p2[(i + 1) % n]);
            dir1[i] = get_dir(p1[i - 1], p1[i], p1[(i + 1) % n]);
            dir2[i] = get_dir(p2[i - 1], p2[i], p2[(i + 1) % n]);
        }
        max1 = -1, max2 = -1;
        for(int i = 0; i < n; i++)
        {
            len1[i] = dis2(p1[i], p1[(i + 1) % n]);
            if(len1[i] > max1) max1 = len1[i];
            len2[i] = dis2(p2[i], p2[(i + 1) % n]);
            if(len2[i] > max2) max2 = len2[i];
        }
        for(int i = 0; i < n; i++)
        {
            len1[i] /= max1;
            len2[i] /= max2;
        }
        if(slove(ang1, ang2, len1, len2, dir1, dir2, n)) printf("similar\n");
        else printf("dissimilar\n");
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值