华为机试题-从(0,0)开始,计算绘图面积-Java

代码在最后面

1 题目描述

绘图机器的绘图笔初始位置在原点(0,0),机器启动后按照以下规则来进行绘制直线。

  1. 尝试沿着横线坐标正向绘制直线直到给定的终点E。
  2. 期间可以通过指令在纵坐标轴方向进行偏移,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);
    }
}

  • 4
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值