1 solutions
-
0
题面描述
塔子哥接到一项任务,需要在一条长为 公里的河流上监测水质。河流沿线有 个候选地点适合建设水质监测站,每个监测站的覆盖半径为 公里,建设一个监测站的成本为 。任务是计算出最少需要多少经费才能覆盖整条河流,如果无法通过在所有候选地点建设监测站来实现覆盖,则输出 "-1"。输入包括河流长度、覆盖半径、建设成本以及候选地点的具体位置,输出则是最少经费或 "-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; // 将候选基站位置标记为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即可 cout << ans << endl; // 输出总费用 return 0; } f = true; // 标记找到基站 break; // 跳出内层循环 } } if (!f) { // 如果当前地址没有找到可用基站 cout << -1 << endl; // 输出-1表示无法覆盖 return 0; } } cout << ans << endl; // 输出最终所需的总费用 return 0; }
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
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); }); });
- 1
Information
- ID
- 29
- Time
- 1000ms
- Memory
- 256MiB
- Difficulty
- 5
- Tags
- # Submissions
- 80
- Accepted
- 15
- Uploaded By