题目概述
直角坐标系中,一个机器人从任意点出发进行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", ×);//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