代码在最后面
1 题目描述
绘图机器的绘图笔初始位置在原点(0,0),机器启动后按照以下规则来进行绘制直线。
- 尝试沿着横线坐标正向绘制直线直到给定的终点E。
- 期间可以通过指令在纵坐标轴方向进行偏移,offset Y为正数表示正向偏移,为负数表示负向偏移。
现在给定的横坐标终点值E以及若干条绘制指令,请计算绘制的直线和横坐标轴以及x=E的直线组成的图形面积。
2 输入描述
首行为两个整数N和E,表示有N条指令,机器运行的横坐标终点值E。接下来N行每行两个整数表示一条绘制指令X offsetY。用例保证横坐标X以递增排序的方式出现,且不会出现相同横坐标X。
取值范围:
0<N<=10000
0<=X<=E<=20000
-10000<=offsetY<=10000
3 输出描述
一个整数表示计算得到的面积用例保证结果范围在0到4294967295之内。
4 示例
4.1 示例1
输入	
4 10
1 1
2 1
3 1
4 -2
输出	
12
解释:
 根据上述指令,绘制图形如下图所示:
 
 如图,蓝色和红色围起来的,1+2+3+6 = 12
4.2 示例2
输入	
2 4
0 1
2 -2
输出	
4
解释:
 根据上述指令,绘制图形如下图所示:
 
 2 + 2 = 4
5 代码解题
思路:每个图形可以切割为多个矩形,然后求矩形面积和即可。例如示例1,可以做如下切割:
 
 可以观察到,总面积 = 矩形1 + 矩形2 + 矩形3 + 矩形4。
 每个矩形的面积取决于左上角的点和右上角的点【如果在X轴下方,则是左下和右下】,而根据题意,会提供X offset Y,也就是说,后一个点的X是右上点的x值坐标,前一个点的X是左上点的x值坐标,整体高度取决于前一个点的高度。
 例如:
 1 1 // 第一次输入
 2 1 // 第二次输入
 4 1 // 第三次输入
 连续起来,可以得到第一次和第二次输入的X轴宽度为 2 - 1 = 1,高度取第一个点的输入值为 1。依次类推,第二个矩形X轴宽 2 = 4 - 2,高为2【理解题意,是累加的】。
 由此,可得整体解题思路为,记每次输入的前一个点的坐标为(x0, y0),当前输入的值为 (w, h),两点之间的和X轴组成的面积 = (w - X0) * abs(y0),更新x0 = w; y0 = y0 + h即可得下次输入时的上一个点信息。同时考虑到最终点E的闭合问题,默认增加一次最后输入值为 (E,-y0),即满足x = E的线信息。
 但是实际计算过程中,我们只需要左上角的点即可,因为相邻两个矩形之间,是紧凑的,后一个点的Y值并不会考虑在计算范围内。
5.1 解法一
记录所有输入的点,然后for循环算出面积求和
import java.util.Scanner;
public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        String line = scanner.nextLine();
        String[] split = line.split(" ");
        final int N = Integer.parseInt(split[0]);
        final int E = Integer.parseInt(split[1]);
        int[][] points = new int[N + 2][2];
        // 录入起点
        points[0] = new int[]{0, 0};
        // 录入终点,最后一个点的右上角不用考虑,因为用不到,所以用 0 代替
        points[N + 1] = new int[]{E, 0};
        for (int i = 1; i < N + 1; i++) {
            String c = scanner.nextLine();
            String[] arr = c.split(" ");
            int x = Integer.parseInt(arr[0]);
            int y = Integer.parseInt(arr[1]) + points[i - 1][1];
            points[i] = new int[]{x, y};
        }
        scanner.close();
        long area = calcArea(points);
        System.out.println(area);
    }
    // 根据点,计算面积
    public static long calcArea(int[][] points){
        int len = points.length;
        long area = 0;
        for (int i = 1; i < len; ++i) {
            area += (long) (points[i][0] - points[i - 1][0]) * Math.abs(points[i - 1][1]);
        }
        return area;
    }
}
解法二
其实没有必要罗列这些点,可以在每次输入的时候,就直接计算面积,然后累加。优化上面的代码,如下:
import java.util.Scanner;
public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        String line = scanner.nextLine();
        String[] split = line.split(" ");
        final int N = Integer.parseInt(split[0]);
        final int E = Integer.parseInt(split[1]);
        long area = 0;
        int x = 0, y = 0;
        for (int i = 1; i < N + 1; i++) {
            String c = scanner.nextLine();
            String[] arr = c.split(" ");
            int inputX = Integer.parseInt(arr[0]);
            int inputY = Integer.parseInt(arr[1]);
            area += (long) (inputX - x) * Math.abs(y);
            x = inputX;
            y += inputY;
        }
        scanner.close();
        System.out.println(area);
    }
}



















