【备战秋招】每日一题:2023.05.17-华为OD机试(第二题)-河流水质监测

news/2024/7/20 19:03:00 标签: 华为od, 算法, 华为, python, java

为了更好的阅读体检,可以查看我的算法学习博客
在线评测链接:P1294

题目描述

塔子哥接到一个新课题,监测一整条河流的水质。

目前塔子哥选择了一条河流进行水质监测,长度为 N N N 公里。经过专业人员勘察,河流沿线有 K K K 个候选地点适合安装水质监测站,每个监测站可以覆盖的长度为半径 R R R 公里,单个监测站建设成本为 M M M

假设塔子哥知道的河流是一条直线,请计算最少需要多少经费建设水质监测站才能完成对整条河流(也就是直线上的每一个实数点)的水质监测。

输入描述

输入第一行包含三个整数 N N N , R R R , M M M .( 1 ≤ N ≤ 3000 , 10 ≤ R ≤ 200 , 1 ≤ M ≤ 100000 1 \leq N \leq 3000,10 \leq R \leq 200,1 \leq M \leq 100000 1N3000,10R200,1M100000 )
输入第二行包含 K K K 个整数 a 1 , a 2 … a K a_1,a_2…a_K a1,a2aK ,表示在高铁沿线的第 a 1 , a 2 … a K a_1,a_2…a_K a1a2aK 公里的地点可以建设基站.( 1 ≤ K ≤ N , 0 ≤ a i ≤ N 1 \leq K \leq N,0 \leq a_i \leq N 1KN,0aiN )

输出描述

输出一个整数,表示最少花费的经费,如果所有候选地点均建设了基站还是无法覆盖则输出 “ − 1 -1 1” 。

样例

输入

100 20 114514
10 30 50

输出

-1

样例2

输入

80 50 114514
0 20 40 60

输出

114514

思路

区间覆盖模板题目,这道题和区间覆盖的区别在于区间固定,我们使用贪心去解决对应的问题。

对于地址 i i i,假设地址小于 i i i的都已经被覆盖,那么如果我们需要覆盖它,我们可以选择的基站位置在范围 [ i − R , i + R ] [i-R,i+R] [iR,i+R]内。假设现在存在两个基站 x x x y y y ( y > x ) (y>x) (y>x)都满足对应的要求,那么我们更偏向于选择 y y y基站,因为 y > x y>x y>x,这样 y y y的基站可以比 x x x基站覆盖更多后面的地址

因此,我们对于每一个地址 i i i,我们都要进行 f o r    j = m i n ( N , i + R )    t o     i − R + 1 , j − = 1 for~~ j = min(N, i+R)~~ to~~~ i-R+1,j-=1 for  j=min(N,i+R)  to   iR+1j=1的循环(这里枚举到 i − R + 1 i-R+1 iR+1,而不枚举到 i − R i-R iR的原因在于一旦选择 i − R i-R iR这个基站,那么肯定存在大于 j j j的部分实数地址无法被覆盖),从 m i n ( N , i + R ) min(N,i+R) min(N,i+R)开始找基站,一旦找到就调用对应的基站。调用基站 j j j后,那么我们范围 [ j − R , j + R ] [j-R,j+R] [jR,j+R]的所有地址都会被覆盖,因此,下一次我们需要枚举的地址应该从 j + R j+R j+R开始(不是 j + R + 1 j+R+1 j+R+1,因为我们需要保证所有实数地址被覆盖,而不是所有整数地址被覆盖)。

类似题目推荐

知识点专栏-贪心

代码

CPP

#include <bits/stdc++.h>
using namespace std;
int N, R, M;
int arr[3005];
int main(){
    cin >> N >> R >> M;
    int num;
    while(cin >> num){
        arr[num] = 1;
    }//输入
    int ans = 0;
    for(int i = 0; i <= N; i++){//枚举所有地址
        bool f = false;
        for(int j = min(N, i + R); j >= i - R + 1; j--){//找对应的基站
            if(arr[j] == 1){
                ans += M;
                i = j + R - 1;//下一次我们需要枚举的地址为j+R
                if(i + 1 == N){//特例,因为我们不需要覆盖大于N的部分实数地址,所以只要覆盖到N即可
                    cout << ans << endl;
                    return 0;
                }
                f = true;//一旦找到就记录,并且推出循环。
                break;
            }
        }
        if(!f){//没找到输出-1
            cout << -1 << endl;
            return 0;
        }
    }
    cout << ans << endl;
    return 0;
}

python_103">python

python">N, R, M = map(int, input().split())
arr = [0] * 3005
line = [int(i) for i in input().split()]#输入
for i in line:
    arr[i] = 1
ans = 0
i = 0

while i <= N:#枚举所有地址
    f = False
    for j in range(min(i + R, N), i - R, -1):#找对应的基站
        if arr[j] == 1:
            ans += M
            i = j + R - 1#下一次我们需要枚举的地址为j+R
            if i + 1 == N:#特例,因为我们不需要覆盖大于N的部分实数地址,所以只要覆盖到N即可
                print(ans)
                exit(0)
            f = True#一旦找到就记录,并且推出循环。
            break
    if not f:#没找到输出-1
        print(-1)
        exit(0)
    i += 1
print(ans)

Java

java">import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int N = scanner.nextInt();
        int R = scanner.nextInt();
        int M = scanner.nextInt();//输入
        int[] arr = new int[3005];

        for (int i = 0; i < 3005; i++) {
            arr[i] = 0;
        }
		int num;
        while(scanner.hasNext()){
            num = scanner.nextInt();
            arr[num] = 1;
        }

        int ans = 0;
        int i = 0;

        while (i <= N) {//枚举所有地址
            boolean f = false;

            for (int j = Math.min(i + R, N); j >= i - R + 1; j--) {//找对应的基站
                if (arr[j] == 1) {
                    ans += M;
                    i = j + R - 1;//下一次我们需要枚举的地址为j+R

                    if (i + 1 == N) {//特例,因为我们不需要覆盖大于N的部分实数地址,所以只要覆盖到N即可
                        System.out.println(ans);
                        System.exit(0);
                    }

                    f = true;//一旦找到就记录,并且退出循环。
                    break;
                }
            }

            if (!f) {//没找到输出-1
                System.out.println(-1);
                System.exit(0);
            }

            i++;
        }

        System.out.println(ans);
    }
}

Go

package main

import (
	"fmt"
)

func main() {
	var N, R, M int
	fmt.Scan(&N, &R, &M)
	arr := make([]int, 3005)//输入

	var num int
	for {
		_, err := fmt.Scan(&num)
		if err != nil {
			break
		}
		arr[num] = 1
	}

	ans := 0
	i := 0

	for i <= N {//枚举所有地址
		f := false

		for j := min(N, i+R); j >= i - R + 1; j-- {//找对应的基站
			if arr[j] == 1 {
				ans += M
				i = j + R - 1//下一次我们需要枚举的地址为j+R

				if i+1 == N {//特例,因为我们不需要覆盖大于N的部分实数地址,所以只要覆盖到N即可
					fmt.Println(ans)
					return
				}

				f = true//一旦找到就记录,并且退出循环。
				break
			}
		}

		if !f {//没找到输出-1
			fmt.Println(-1)
			return
		}

		i++
	}

	fmt.Println(ans)
}

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

Js

const readline = require('readline');

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

let N, R, M;
let arr = new Array(3005).fill(0);

rl.question('', (line1) => {
    const input1 = line1.trim().split(' ').map(Number);
    N = input1[0];
    R = input1[1];
    M = input1[2];

    rl.question('', (line2) => {
        const input2 = line2.trim().split(' ').map(Number);
        for (let i = 0; i < input2.length; i++) {
            arr[input2[i]] = 1;
        }//输入

        let ans = 0;
        let i = 0;

        while (i <= N) {//枚举所有地址
            let f = false;

            for (let j = Math.min(i + R, N); j >= i - R + 1; j--) {//找对应的基站
                if (arr[j] === 1) {
                    ans += M;
                    i = j + R - 1;//下一次我们需要枚举的地址为j+R

                    if (i + 1 === N) {//特例,因为我们不需要覆盖大于N的部分实数地址,所以只要覆盖到N即可
                        console.log(ans);
                        process.exit(0);
                    }

                    f = true;//一旦找到就记录,并且退出循环。
                    break;
                }
            }

            if (!f) {//没找到输出-1
                console.log(-1);
                process.exit(0);
            }

            i++;
        }

        console.log(ans);
        process.exit(0);
    });
});

题目内容均收集自互联网,如如若此项内容侵犯了原著者的合法权益,可联系我: (CSDN网站注册用户名: 塔子哥学算法) 进行删除。


http://www.niftyadmin.cn/n/1008644.html

相关文章

rt thread系统下实现恢复出厂设置功能

修改bootloader和app的分区表&#xff0c;增加factory分区。 qboot软件包里恢复出厂设置分区名字要和实际的一致。 屏蔽掉bootloader里的w25q128.c文件里的config_part分区定义 在qboot.c文件里的static void qbt_thread_entry(void *params)线程里增加查找分区和判断重启次数的…

android 13 横屏

目录&#xff1a;/device/rockchip/rksdk / BoardConfig_xxx.mk # For Recovery Rotation 修改recover TARGET_RECOVERY_DEFAULT_ROTATION ? ROTATION_RIGHT # For Surface Flinger Rotation 修改系统界面 SF_PRIMARY_DISPLAY_ORIENTATION ? 90 实际上 build/make/core/Ma…

金九银十1060+ 道 Java面试题及答案整理(2023最新版)

前言 今年的金三银四可是被裁员疫情搞得人心慌慌&#xff0c;由于大厂纷纷裁员&#xff0c;面试的竞争难度又上一层&#xff0c;不知道你是否在金三银四中拿到 offer&#xff1f;不过这些都过去了&#xff0c;现在马上迎来的是金九银十&#xff0c;按照往年来说&#xff0c;秋…

【UnityDOTS 三】Component的理解

Component的理解 文章目录 Component的理解前言一、托管Component与非托管Component1.非托管Component2.托管Component 二、各功能的Component三、在Editor中的Component的区分总结 前言 Component作为ECS中承载数据的结构&#xff0c;了解他相关内容是非常必要的&#xff0c;…

VB+access智能排课系统的设计与实现

“信息手段革命”转向“信息内容革命”,引发了全球性数字校园建设浪潮。在信息时代的今天,计算机参与事业单位日常业务管理以成为事业单位现代化管理的当务之急。随着电脑的普及与使用,现在的管理也提升了一个档次,渐渐实现了无纸化办公,即从原来的人工记录管理模式转变为…

c++23中的新功能之十平坦容器

一、背景介绍 在前面反复提到过&#xff0c;其实所有的编程语言总体的方向是朝着自然语言化和简单在发展&#xff0c;速度有快慢&#xff0c;但方向基本没有错。这里先回顾一下&#xff0c;在STL中有六大组件&#xff08;侯捷老师的《STL源码剖析》&#xff09;&#xff0c;这…

linux 桌面(交互界面)黑屏

vmware 装的centos 7&#xff0c;一直用的好好地。有一天笔记本关机了。重启之后虚拟机开机用户登录界面是黑色的。能切换到tty2,正常使用。 网上的办法都试过了了不生效。 最后发现在命令行界面启动桌面&#xff08;startx命令&#xff09;可以进入桌面&#xff0c;并提示空间…

初学nacos总结

1、服务雪崩&#xff1a;所有的实例都不可用 2、雪崩保护 保护阈值&#xff1a;0-1 就是百分比 与实例有关 健康实例数/总实例数<保护阈值 会把不健康的实例拿出来用&#xff0c;这就是雪崩保护 3、实例&#xff1a;永久实例 临时实例 临时实例&#xff1a;spring.cloud.n…