UVA 10088 Trees on My Island(求整顶点多边形内部整点数)

558 篇文章 0 订阅
273 篇文章 0 订阅

UVA 10088 Trees on My Island(求整顶点多边形内部整点数)

http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=12&page=show_problem&problem=1029

题意:

       给你一个顶点都是整点的多边形,要你求出该多边形内部的整点个数?

分析:

       假设多边形的面积为S, 内部的整点为A个, 边上的整点为B个. 那么由pick定理可得: A+B/2-1=S. 所以我们只要求出多边形的面积和它边上的整点个数即可.

       由于点是按顺时针或逆时针给出的,所以可以直接用刘汝佳的模板来求多边形面积(本质是把多边形分成一个个的小三角形来求面积和).

       对于多边形边上的整点: 一条由整点构成的线段(线段长度>0)它内部(不包含端点)的整点个数= gcd(线段的X增量,线段的Y增量)-1. 该结论的证明在POJ2954题解中:

http://blog.csdn.net/u013480600/article/details/39269265

本题找int溢出的bug找了半天,哎.

       注意:如果需要用long long 的题目还是劲量所有数据都用long long,因为你没法兼顾到每一个需要强转的int算术表达式.

AC代码:

#include<cstdio>
#include<algorithm>
#include<cmath>
#include<iostream>
using namespace std;
const int maxn=1000+10;
struct Point
{
    int x,y;
    Point(){}
    Point(int x,int y):x(x),y(y){}
}P[maxn];
typedef Point Vector;
Vector operator-(Point A,Point B)
{
    return Vector(A.x-B.x,A.y-B.y);
}
long long Cross(Point A,Point B)
{
    return (long long)A.x*B.y-(long long)A.y*B.x;//严重错误,后面的(long long)忘加了
}
double PolygenArea(Point *p,int n)
{
    double area=0;//错误2,area一定要是double的,如果area为int,那么/2会丢失精度
    for(int i=1;i<n-1;++i)
        area += Cross(p[i]-p[0], p[i+1]-p[0]);//错误1,这里不能加abs求绝对值
    return fabs(area)/2;
}
int gcd(int a,int b)
{
    return b==0? a : gcd(b,a%b);
}
int PointInLine(Point A,Point B)//整点线段AB内部的整点数
{
    int dx=abs(A.x-B.x),dy=abs(A.y-B.y);
    if(dx==0 && dy==0) return 0;
    return gcd(dx,dy)-1;
}
long long PointInPolygen(Point *p,int n)//整点多边形内部的整点数
{
    long long s=PolygenArea(p,n);
    long long b=n;//在多边形边上的整点数目
    for(int i=0;i<=n-1;++i)
        b += PointInLine(p[i],p[(i+1)%n]);
    return s-b/2+1;
}

int main()
{
    int n;
    while(scanf("%d",&n)==1 && n)
    {
        for(int i=0;i<n;++i) scanf("%d%d",&P[i].x,&P[i].y);
        printf("%lld\n",PointInPolygen(P,n));
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值