poj 1265

本文探讨了计算几何中一个多边形的面积及其内部和边界上的格点数量问题。通过Pick公式逆向推导出格点数,并介绍了如何计算简单多边形的面积。文章还提供了详细的算法实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目概述

直角坐标系中,一个机器人从任意点出发进行N次移动,每次向右移动dx,向上移动dy,最后会围成一个封闭图形,求该图形的内部和边上共有多少格点(横纵坐标都为整数的点),以及该图形的面积

时限

1000ms/3000ms

输入

第一行times,其后有times组数据,每组数据第一行正整数N,其后N行,每行两个整数dx,dy

限制

3<=N<=100;-100<=dx,dy<=100;(dx,dy)!=(0,0)

输出

每组数据在两行中输出,第一行字符串
Scenario #A:
其中A代表数据序数,从1开始,第二行两个整数和一个保留一位小数的浮点数,分别代表内部和边上的格点数,以及图形面积,两组输出间有一个空行

样例输入

2
4
1 0
0 1
-1 0
0 -1
7
5 0
1 3
-2 2
-1 0
0 -3
-3 1
0 -3

样例输出

Scenario #1:
0 4 1.0

Scenario #2:
12 16 19.0

讨论

计算几何,求简单多边形面积,以及pick公式的应用,还有如何算格点数,先说说pick公式,以I代表内部格点数,E代表边上格点数,A代表图形面积,公式为A=I+E/2-1这里需要反过来用,I=A-E/2+1,这又要说如何求边上格点数,如果边dx和dy都非零,那么经过的格点数是其最大公倍数+1,当然,如果要算一整个图形的,+1的点会被上一条边计算,也就不需要加了,如果有一个是0,那这条边就会经过dx+dy个格点,无论哪一个是0,最后还是说面积,其实poj 3348,poj 1654的算面积法是可以应对任何简单多边形的,无论凹凸,这就是有向面积的好处,具体的实现细节由于可以参考另外两道题,不再赘述

题解状态

184K,0MS,C++,1030B

题解代码

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
#define INF 0x3f3f3f3f  
#define MAXN 10003
#define memset0(a) memset(a,0,sizeof(a))
#define EPS 1e-6

int N;//移动次数
bool f;//控制空行输出
int gcd(int a, int b)//greatest_common_divisor 最大公约数 这个想必人人都会 可惜额只会这一种形式 以前见过递归式的 觉得常数略大就没留心
{
    while (b) {
        int c = a%b;
        a = b;
        b = c;
    }
    return a;
}
int xp(int x1, int y1, int x2, int y2, int x3, int y3)
{
    return (x1 - x2)*(y3 - y2) - (y1 - y2)*(x3 - x2);
}
void fun()
{
    int x1 = 0, y1 = 0, x2, y2, E = 0, I = 0, A = 0;//前后两次的位置 默认是从原点开始 edge 边上格点 inside 内部格点 area 面积
    for (int p = 0; p < N; p++) {
        int dx, dy;//移动的相对位置
        scanf("%d%d", &dx, &dy);//input
        x2 = x1 + dx, y2 = y1 + dy;
        A += xp(x1, y1, 0, 0, x2, y2);
        if (dx&&dy)
            E += gcd(abs(dx), abs(dy));//注意dx,dy是有正负的 而gcd只能处理正数
        else
            E += abs(dx) + abs(dy);//同理
        x1 = x2, y1 = y2;
    }
    printf("%d %d %.1lf\n", (A + 2 - E) / 2, E, A / 2.0);//output//之前面积没有除以2 因而pick公式是加倍后的形式
    f = 1;
}
int main(void)
{
    //freopen("vs_cin.txt", "r", stdin);
    //freopen("vs_cout.txt", "w", stdout);

    int times;
    scanf("%d", &times);//input
    for (int p = 0; p < times; p++) {
        scanf("%d", &N);//input
        if (f)
            printf("\n");//output
        printf("Scenario #%d:\n", p + 1);//output//先把这些固定的输出搞定
        fun();
    }
}

EOF

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值