例题6.18 绿色的世界 UVa11017

来源:互联网 发布:淘宝店长和运营的区别 编辑:程序博客网 时间:2024/05/21 16:23

1.题目描述:点击打开链接

2.解题思路:本题利用Pick定理解决。Pick定理讲的是:给定一个顶点都是整点的简单多边形,其面积A,内部格点的数目I与边上的格点数目B的关系是:A=I+B/2-1。这样,我们就能算出I=A-B/2+1。不过,这样并不能完整的解决本题,因为题目中要求计算每个小菱形的中点有多少个。由于错切变换不会影响内部格点的个数,因此我们不妨仍然理解为在相互垂直的x-y坐标系中,那么等价于要我们找内部x,y坐标的小数部分都是0.5的点有多少个。此时我们可以想办法把它们也都变成“整点”。最直观的办法就是将坐标系顺时针旋转45度,这样,原来的整点还是整点,小数部分均为0.5的点也成了整点。因此,我们可以统计在原坐标系下的内部整点数,再统计坐标系旋转后的内部整点数,后者减去前者就是答案。

3.代码:

#include<iostream>#include<algorithm>#include<cassert>#include<string>#include<sstream>#include<set>#include<bitset>#include<vector>#include<stack>#include<map>#include<queue>#include<deque>#include<cstdlib>#include<cstdio>#include<cstring>#include<cmath>#include<ctime>#include<cctype>#include<functional>#pragma comment(linker, "/STACK:1024000000,1024000000")using namespace std;#define me(s)  memset(s,0,sizeof(s))#define rep(i,n) for(int i=0;i<(n);i++)typedef long long LL;typedef unsigned int uint;typedef unsigned long long ull;typedef pair <int, int> P;const double PI = acos(-1.0);struct Point {  int x, y;  Point(int x=0, int y=0):x(x),y(y) { }};typedef Point Vector;Vector operator + (const Vector& A, const Vector& B) { return Vector(A.x+B.x, A.y+B.y); }Vector operator - (const Point& A, const Point& B) { return Vector(A.x-B.x, A.y-B.y); }double Cross(const Vector& A, const Vector& B) { return (LL)A.x*B.y - (LL)A.y*B.x; }LL PolygonArea2(const vector<Point>& p) //计算多边形面积*2的结果{  int n = p.size();  LL area2 = 0;  for(int i = 1; i < n-1; i++)    area2 += Cross(p[i]-p[0], p[i+1]-p[0]);  return abs(area2);}inline int gcd(int a, int b) {  return b == 0 ? a : gcd(b, a%b);}LL count_on_segment(const Point& a, const Point& b)//计算线段a-b上整点的个数,如果不计算端点,就是gcd(dx,dy)-1个,这不难通过参数表达式得到{  return gcd(abs(b.x-a.x), abs(b.y-a.y)) - 1;}LL count_inside_polygon(const vector<Point>& poly) //利用Pick定理可得:I=A-B/2+1{  int n = poly.size();  LL A2 = PolygonArea2(poly);  int B = n;  for(int i = 0; i < n; i++)    B += count_on_segment(poly[i], poly[(i+1)%n]);  return (A2 - B) / 2 + 1;//注意:这里的A2是多边形面积*2的结果,因此也要除以2}LL count(const vector<Point>& poly) //查找x,y小数部分都是0.5的点{  vector<Point> poly2;  for(int i = 0; i < poly.size(); i++)    poly2.push_back(Point(poly[i].x-poly[i].y, poly[i].x+poly[i].y));  return count_inside_polygon(poly2) - count_inside_polygon(poly);  //相减就是答案}int main() {  int d, theta, N, x, y;   //这里给定的d,theta只是用来计算面积的,错切变换后相当于x-y坐标系下的面积乘以系数d*d*sin(theta)  while(scanf("%d%d%d", &d, &theta, &N) == 3 && d)     {        vector<Point> poly;        for(int i = 0; i < N; i++) {            scanf("%d%d", &x, &y);        poly.push_back(Point(x, y));    }    LL area2 = PolygonArea2(poly);    printf("%lld %.0lf\n", count(poly), sin((double)theta / 180 * PI) * d * d * area2 / 2.0);//area2/2才是原坐标系的面积  }  return 0;}

0 0
原创粉丝点击