• POJ 1265 -- Area (Pick定理+多边形面积)


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

    Area
    Time Limit: 1000MS   Memory Limit: 10000K
    Total Submissions: 7080   Accepted: 3037

    Description

    Being well known for its highly innovative products, Merck would definitely be a good target for industrial espionage. To protect its brand-new research and development facility the company has installed the latest system of surveillance robots patrolling the area. These robots move along the walls of the facility and report suspicious observations to the central security office. The only flaw in the system a competitor抯 agent could find is the fact that the robots radio their movements unencrypted. Not being able to find out more, the agent wants to use that information to calculate the exact size of the area occupied by the new facility. It is public knowledge that all the corners of the building are situated on a rectangular grid and that only straight walls are used. Figure 1 shows the course of a robot around an example area. 

     
    Figure 1: Example area. 

    You are hired to write a program that calculates the area occupied by the new facility from the movements of a robot along its walls. You can assume that this area is a polygon with corners on a rectangular grid. However, your boss insists that you use a formula he is so proud to have found somewhere. The formula relates the number I of grid points inside the polygon, the number E of grid points on the edges, and the total area A of the polygon. Unfortunately, you have lost the sheet on which he had written down that simple formula for you, so your first task is to find the formula yourself. 

    Input

    The first line contains the number of scenarios. 
    For each scenario, you are given the number m, 3 <= m < 100, of movements of the robot in the first line. The following m lines contain pairs 揹x dy�of integers, separated by a single blank, satisfying .-100 <= dx, dy <= 100 and (dx, dy) != (0, 0). Such a pair means that the robot moves on to a grid point dx units to the right and dy units upwards on the grid (with respect to the current position). You can assume that the curve along which the robot moves is closed and that it does not intersect or even touch itself except for the start and end points. The robot moves anti-clockwise around the building, so the area to be calculated lies to the left of the curve. It is known in advance that the whole polygon would fit into a square on the grid with a side length of 100 units. 

    Output

    The output for every scenario begins with a line containing 揝cenario #i:� where i is the number of the scenario starting at 1. Then print a single line containing I, E, and A, the area A rounded to one digit after the decimal point. Separate the three numbers by two single blanks. Terminate the output for the scenario with a blank line.

    Sample Input

    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
    

    Sample Output

    Scenario #1:
    0 4 1.0
    
    Scenario #2:
    12 16 19.0


    题意:从起始点开始,给出机器人每次在方格上移动的横坐标变化量和纵坐标变化量,求移动轨迹所形成的多边形的内部格点,边上格点,面积。
    解析:gcd()求边上格点数,叉积求多边形面积,Pick定理求内部格点数。

    求在边上的格点数:
    一条端点在格点上的线段覆盖的点数:gcd(tx, ty)+1 tx,ty分别为线段横向长度和纵向长度;
    证明:若tx,ty不为0,将线段看为直角三角形的斜边,tx看为底直角边,ty看为竖直角边,tx/gcd(tx, ty)与ty/gcd(tx, ty)互质,当两直角边互质,斜边除了底端格点外,就只有一个格点;
    将两互质的直角边乘以gcd(tx, ty),斜边长度变为gcd(tx, ty)倍,即都变为了原来的长度,斜边除了底端外的格点数也变为1 * gcd(tx, ty)个;若tx或ty为0,或者都为0,显然式子也成立,故覆盖点数为gcd(tx, ty)+1得证;
    为什么当两直角边互质,斜边除了底端格点外就只有一个格点:可用反证法,若此时有多个格点,则三边长同时除以格点数后三端点仍会在格点上,即两直角边同时除以一个数后仍为整数,这与两直角边互质矛盾。

    向量叉积:
    ① 以向量 (a, b) 和 (c, d) 为邻边,构成的平行四边形的面积正好是 |ad – bc|。
    ② A.cross(B)可得到两个向量之间的顺逆关系:> 0 表示 A在B的顺时针方向; <0表示A在B的逆时针方向; =0 表示则为共线向量(有可能同向,有可能反向);

    多边形面积:

    1) △ABC的面积为向量AB与向量AC的叉乘的一半。

    2)对于一个多边形,选定一个顶点P1,与其他顶点连线,可将多边形分为若干个三角形。

    3)多边形面积为 abs(Sum{CrossMul(A,B,P1)|A,B为相邻的两个顶点}) (先求和再取abs,否则对于凹多边形会出错,由上述向量叉积②可理解)。

    Pick定理:

    一个计算点阵中顶点在格点上的多边形面积公式:S = a + b / 2 - 1,其中a表示多边形内部的点数,b表示多边形边界上的点数,S表示多边形的面积。

    此题注意:题目要求答案三个数之间用两个空格隔开,其实一个空格才能AC;下面这段代码用C++提交能AC,G++却WA。

     1 #include <iostream>
     2 #include <cstdlib>
     3 #include <iomanip>
     4 using namespace std;
     5 int gcd(int a, int b) {
     6     return b ? gcd(b, a % b) : a;
     7 }
     8 int sumarea(int x1, int y1, int x2, int y2) {
     9     return x1 * y2 - x2 * y1;
    10 }
    11 
    12 int main() {
    13     int t, times = 0;
    14     cin >> t;
    15     while (t--) {
    16         int n; cin >> n;
    17         int area = 0;
    18         int x = 0, y = 0, dx = 0, dy = 0; // 设起始点为(0, 0)
    19         int ans2 = 0;
    20         for (int i = 1; i <= n; i++) {
    21             int tx, ty;
    22             cin >> tx >> ty;  // x和y的变化量
    23             dx = x + tx, dy = y + ty;   // 新点坐标
    24             ans2 += gcd(abs(tx), abs(ty)); // 求出边上点的数量
    25             area += sumarea(x, y, dx, dy);  // 旧点坐标和新点坐标,也是原点到这两点的向量
    26             x = dx, y = dy;   // 更新旧点
    27         }
    28         area = abs(area);
    29         double ans3 = (double)area / 2.0;
    30         int ans1 = (area + 2 - ans2) / 2;
    31         cout << "Scenario #" << ++times << ":
    " << ans1 << "  " << ans2 << "  " << fixed << setprecision(1) << ans3 << endl << endl;
    32     }
    33     return 0;
    34 }
    View Code

    一道更简单的类型题:POJ 2954 -- Triangle

     1 // 向量叉积:以向量 (a, b) 和 (c, d) 为邻边,构成的平行四边形的面积正好是 |ad – bc|
     2 // Pick定理:用I表示多边形内部的点数,E来表示多边形边上的点数,S表示多边形的面积, 满足S = I + E / 2 - 1;
     3 #include <iostream>
     4 #include <cstdlib>
     5 using namespace std;
     6 int gcd(int a, int b) {
     7     return b ? gcd(b, a % b) : a;
     8 }
     9 
    10 int main() {
    11     int ax, ay, bx, by, cx, cy;
    12     while (cin >> ax >> ay >> bx >> by >> cx >> cy && (ax || ay || bx || by || cx || cy)) {
    13         int a = gcd(abs(ax - bx), abs(ay - by)) - 1;
    14         int b = gcd(abs(bx - cx), abs(by - cy)) - 1;
    15         int c = gcd(abs(ax - cx), abs(ay - cy)) - 1;
    16         int S = abs((ax - bx) * (ay - cy) - (ay - by) * (ax - cx));  // 三角形面积的两倍
    17         cout << (S + 2 - a - b - c - 3) / 2 << endl;
    18     }
    19     return 0;
    20 }
    View Code

    一道比上面那道还简单的求边上格点数裸题:ZZNUOJ 1989 -- How many?

     1 #include <iostream>
     2 #include <cstdlib>
     3 using namespace std;
     4 typedef long long LL;
     5 LL gcd(LL a, LL b) {
     6     return b ? gcd(b, a % b) : a;
     7 }
     8 
     9 int main() {
    10     LL t, ax, ay, bx, by;
    11     cin >> t;
    12     while (t--) {
    13         cin >> ax >> ay >> bx >> by;
    14         cout << gcd(abs(ax - bx), abs(ay - by)) + 1 << endl;
    15     }
    16     return 0;
    17 }
    View Code
    作者:_kangkang
    本文版权归作者和博客园共有,欢迎转载,但必须给出原文链接,并保留此段声明,否则保留追究法律责任的权利。
  • 相关阅读:
    MySQL数据库----数据类型
    MySQL数据库----安装
    I2c串行总线组成及其工作原理
    感慨
    液晶操作
    串口通信
    9.19AD和DA操作
    9.19键盘的应用
    9.17键盘的操作
    9.15学习笔记
  • 原文地址:https://www.cnblogs.com/kangkang-/p/8418504.html
Copyright © 2020-2023  润新知