(B卷,100分)- 路灯照明问题(Java & JS & Python & C)

题目描述

在一条笔直的公路上安装了N个路灯,从位置0开始安装,路灯之间间距固定为100米。
每个路灯都有自己的照明半径,请计算第一个路灯和最后一个路灯之间,无法照明的区间的长度和。

输入描述

第一行为一个数N,表示路灯个数,1<=N<=100000
第二行为N个空格分隔的数,表示路灯的照明半径,1<=照明半径<=100000*100

输出描述

第一个路灯和最后一个路灯之间,无法照明的区间的长度和

用例

输入 2
50 50
输出 0
说明 路灯1覆盖0-50,路灯2覆盖50-100,路灯1和路灯2之间(0米-100米)无未覆盖的区间。
输入 4
50 70 20 70

输入

解释

路灯1 覆盖0-50
路灯2 覆盖30-170
路灯3 覆盖180-220
路灯4 覆盖230-370
输出 20
说明 [170,180],[220,230],两个未覆盖的区间,总里程为20

题目解析

本题可以转化为区间问题。

每个路灯的位置都是确定,假设路灯的索引为 i,那么其位置就是 i * 100。

根据第二行输入的路灯的照明半径数组arr,我们可以基于路灯的位置,求得路灯的照明范围区间

假设center = i * 100,r = arr[i],那么照明范围区间即为:[center – r, center + r]

这样的话,我们就得到了一组区间。

接下来,我们就需要将这些区间进行合并,合并后,求剩余没有交集的区间的间隙之和就是题解。

这里区间合并是有技巧的,我们一般:

  • 先将区间按照起始位置进行升序
  • 如果起始位置相同,则再按照结束位置降序

这样排序的好处是,所有区间都按照起始位置升序排序了,比如第一个ran[0]和第二个区间ran[1],我们可以确定:ran[0].start <= ran[1].start

由于这两个区间的起始位置关系已经确定了,判断这两个区间是否有交集,只要看ran[0].end和ran[1].start即可,如果ran[0].end > ran[1].start,则说明这两个区间有交集,可以合并。

另外,如果ran[0]和ran[1]的起始位置相同的话,则上面排序还会按照结束位置进行降序,即必然ran[0].end >= ran[1].end。

这样排序的好处是,后面区间的结束位置小于前面区间的结束位置时,可以直接放心并入前面区间,而不需要再进行起始位置相同的两个区间的结束位置比较。

JavaScript算法源码

/* JavaScript Node ACM模式 控制台输入获取 */
const readline = require("readline");

const rl = readline.createInterface({
  input: process.stdin,
  output: process.stdout,
});

const lines = [];
rl.on("line", (line) => {
  lines.push(line);

  if (lines.length === 2) {
    const n = lines[0] - 0;
    const arr = lines[1].split(" ").map(Number);

    console.log(getResult(n, arr));

    lines.length = 0;
  }
});

function getResult(n, arr) {
  const ranges = [];

  for (let i = 0; i < n; i++) {
    const center = i * 100;
    ranges.push([center - arr[i], center + arr[i]]);
  }

  // 按起始位置升序,起始位置相同,则继续按结束位置降序
  ranges.sort((a, b) => (a[0] != b[0] ? a[0] - b[0] : b[1] - a[1]));

  let ans = 0;

  let t = ranges[0][1]; // 上一个区间的结束位置
  for (let i = 1; i < n; i++) {
    const [s, e] = ranges[i]; // 当前区间的【开始位置,结束位置】

    // 有交集
    if (t >= s) {
      // 合并后的新区间将变为下一轮的上一个区间,t为新区间的结束位置
      t = Math.max(e, t);
    } else {
      // 没有交集,则统计区间间隙 s - t
      ans += s - t;
      // 当前区间变为下一轮的上一个区间,更新t
      t = e;
    }
  }

  return ans;
}

Java算法源码

import java.util.Arrays;
import java.util.Scanner;

public class Main {
  public static void main(String[] args) {
    Scanner sc = new Scanner(System.in);

    int n = sc.nextInt();

    int[][] ranges = new int[n][2];
    for (int i = 0; i < n; i++) {
      int center = i * 100;
      int r = sc.nextInt();
      ranges[i][0] = center - r;
      ranges[i][1] = center + r;
    }

    System.out.println(getResult(n, ranges));
  }

  public static int getResult(int n, int[][] ranges) {
    int ans = 0;

    // 按起始位置升序,起始位置相同,则继续按结束位置降序
    Arrays.sort(ranges, (a, b) -> a[0] != b[0] ? a[0] - b[0] : b[1] - a[1]);

    int t = ranges[0][1]; // 上一个区间的结束位置

    for (int i = 1; i < n; i++) {
      // 当前区间的【开始位置,结束位置】
      int s = ranges[i][0];
      int e = ranges[i][1];

      // 有交集
      if (t >= s) {
        // 合并后的新区间将变为下一轮的上一个区间,t为新区间的结束位置
        t = Math.max(e, t);
      } else {
        // 没有交集,则统计区间间隙 s - t
        ans += s - t;
        // 当前区间变为下一轮的上一个区间,更新t
        t = e;
      }
    }

    return ans;
  }
}

Python算法源码

# 输入获取
n = int(input())
arr = list(map(int, input().split()))


# 算法入口
def getResult():
    rans = []

    for i in range(n):
        center = i * 100
        rans.append([center - arr[i], center + arr[i]])

    # 按起始位置升序,起始位置相同,则继续按结束位置降序
    rans.sort(key=lambda ran: (ran[0], -ran[1]))

    ans = 0

    t = rans[0][1]  # 上一个区间的结束位置
    for i in range(1, n):
        s, e = rans[i]  # 当前区间的【开始位置,结束位置】

        # 有交集
        if t >= s:
            # 合并后的新区间将变为下一轮的上一个区间,t为新区间的结束位置
            t = max(e, t)
        else:
            # 没有交集,则统计区间间隙 s - t
            ans += s - t
            #  当前区间变为下一轮的上一个区间,更新t
            t = e

    return ans


# 算法调用
print(getResult())

C算法源码

#include <stdio.h>
#include <stdlib.h>

#define MAX(a,b) (a) > (b) ? (a) : (b)

int getResult(int n, int ranges[][2]);
int cmp(const void* a, const void* b);

int main() {
    int n;
    scanf("%d", &n);

    int ranges[n][2];
    for(int i=0; i<n; i++) {
        int center = i * 100;

        int r;
        scanf("%d", &r);

        ranges[i][0] = center - r;
        ranges[i][1] = center + r;
    }

    printf("%dn", getResult(n, ranges));

    return 0;
}

int getResult(int n, int ranges[][2]) {
    int ans = 0;

    // 按起始位置升序,起始位置相同,则继续按结束位置降序
    qsort(ranges, n, sizeof(int*), cmp);

    int t = ranges[0][1]; // 上一个区间的结束位置

    for(int i=1; i<n; i++) {
        // 当前区间的【开始位置,结束位置】
        int s = ranges[i][0];
        int e = ranges[i][1];

        if(t >= s) {
            // 有交集
            // 合并后的新区间将变为下一轮的上一个区间,t为新区间的结束位置
            t = MAX(e, t);
        } else {
            // 没有交集,则统计区间间隙 s - t
            ans += s - t;
            // 当前区间变为下一轮的上一个区间,更新t
            t = e;
        }
    }

    return ans;
}

int cmp(const void* a, const void* b) {
    int* A = (int*) a;
    int* B = (int*) b;
    return A[0] != B[0] ? A[0] - B[0] : B[1] - A[1];
}

免责声明:

1、IT资源小站为非营利性网站,全站所有资料仅供网友个人学习使用,禁止商用
2、本站所有文档、视频、书籍等资料均由网友分享,本站只负责收集不承担任何技术及版权问题
3、如本帖侵犯到任何版权问题,请立即告知本站,本站将及时予与删除下载链接并致以最深的歉意
4、本帖部分内容转载自其它媒体,但并不代表本站赞同其观点和对其真实性负责
5、一经注册为本站会员,一律视为同意网站规定,本站管理员及版主有权禁止违规用户
6、其他单位或个人使用、转载或引用本文时必须同时征得该帖子作者和IT资源小站的同意
7、IT资源小站管理员和版主有权不事先通知发贴者而删除本文

0

评论0

站点公告

没有账号?注册  忘记密码?