路灯照明问题

路灯照明问题

真题目录: 点击去查看

E B卷 100分题型

题目描述

在一条笔直的公路上安装了N个路灯,从位置0开始安装,路灯之间间距固定为100米。

每个路灯都有自己的照明半径,请计算第一个路灯和最后一个路灯之间,无法照明的区间的长度和。

输入描述

第一行为一个数N,表示路灯个数,1<=N<=100000

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

输出描述

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

用例1

输入

2
50 50

输出

none 复制代码
0

说明

路灯1覆盖0-50,路灯2覆盖50-100,路灯1和路灯2之间(0米-100米)无未覆盖的区间。

用例2

输入

4
50 70 20 70

输出

none 复制代码
20

说明

[170,180],[220,230],两个未覆盖的区间,总里程为20

题解

思路:

  • 比较简单的一道题, 区间合并(注意可能出现递归合并)

c++

c++ 复制代码
#include<iostream>
#include<vector>
#include<string>
#include <utility> 
#include <sstream>
#include<algorithm>
#include<stack>
using namespace std;

int main() {
    int n ;
    cin >> n;
    vector<int> ans(n);
    stack<pair<int,int>> stk;
    for (int i = 0; i < n; i++) {
        cin >> ans[i];
        int left = (i * 100) - ans[i];
        int right = (i*100) + ans[i];
        // 递归区间合并
        while (!stk.empty() && stk.top().second >= left) {
            pair<int,int> tmp = stk.top();
            stk.pop();
            left = min(tmp.first, left);
            right = max(tmp.second, right); 
        }
        stk.push({left, right});
    }
    int res = 0;
    // 计算多个区间中空白照明长度
    while (stk.size() != 1) {
        pair<int,int> top = stk.top();
        stk.pop();
        res += top.first - stk.top().second;
    } 

    cout << res;
}

JAVA

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

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())

JavaScript

js 复制代码
/* 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;
}

Go

go 复制代码
package main

import (
	"fmt"
)

func main() {
	var n int
	fmt.Scan(&n)

	ans := make([]int, n)
	for i := 0; i < n; i++ {
		fmt.Scan(&ans[i])
	}

	type Interval struct {
		left  int
		right int
	}

	stack := []Interval{}
	for i := 0; i < n; i++ {
		left := i*100 - ans[i]
		right := i*100 + ans[i]

		// 合并重叠区间
		for len(stack) > 0 && stack[len(stack)-1].right >= left {
			top := stack[len(stack)-1]
			stack = stack[:len(stack)-1]
			left = min(top.left, left)
			right = max(top.right, right)
		}
		stack = append(stack, Interval{left, right})
	}

	// 计算区间之间的空白长度
	res := 0
	for i := 1; i < len(stack); i++ {
		res += stack[i].left - stack[i-1].right
	}

	fmt.Println(res)
}

func min(a, b int) int {
	if a < b {
		return a
	}
	return b
}

func max(a, b int) int {
	if a > b {
		return a
	}
	return b
}
相关推荐
利刃大大26 分钟前
【回溯+剪枝】找出所有子集的异或总和再求和 && 全排列Ⅱ
c++·算法·深度优先·剪枝
皮卡丘のcoding1 小时前
蓝桥杯备赛练习题01
职场和发展·蓝桥杯
Rachela_z1 小时前
代码随想录算法训练营第十四天| 二叉树2
数据结构·算法
细嗅蔷薇@1 小时前
迪杰斯特拉(Dijkstra)算法
数据结构·算法
追求源于热爱!1 小时前
记5(一元逻辑回归+线性分类器+多元逻辑回归
算法·机器学习·逻辑回归
不过四级不改名6771 小时前
蓝桥杯嵌入式uart,iic,adc_scan模版
职场和发展·蓝桥杯
ElseWhereR1 小时前
C++ 写一个简单的加减法计算器
开发语言·c++·算法
Smark.2 小时前
Gurobi基础语法之 addConstr, addConstrs, addQConstr, addMQConstr
算法
S-X-S2 小时前
算法总结-数组/字符串
java·数据结构·算法
努力学习java的哈吉米大王3 小时前
数据结构-队列
数据结构