扫地机器人(第十届蓝桥杯研究生组)
题目:
小明公司的办公区有一条长长的走廊,由 N 个方格区域组成,如下图所示。
走廊内部署了 K 台扫地机器人,其中第 ii 台在第 Ai 个方格区域中。
已知扫地机器人每分钟可以移动到左右相邻的方格中,并将该区域清扫干净。
请你编写一个程序,计算每台机器人的清扫路线,使得
- 它们最终都返回出发方格,
- 每个方格区域都至少被清扫一遍,
- 从机器人开始行动到最后一台机器人归位花费的时间最少。
注意多台机器人可以同时清扫同一方块区域,它们不会互相影响。
输出最少花费的时间。
在上图所示的例子中,最少花费时间是 66。
第一台路线:2−1−2−3−4−3−2,清扫了 1、2、3、4 号区域。
第二台路线 5−6−7−6−5,清扫了 5、6、7。
第三台路线 10−9−8−9−10,清扫了 8、9和 10。
输入格式
第一行包含两个整数 N 和 K。
接下来 K 行,每行一个整数 Ai。
输出格式
输出一个整数表示答案。
数据范围
1≤K<N≤1e5,
1≤Ai≤N
输入样例:
10 3
5
2
10
输出样例:
6
分析思路
最关键就是将题目条件转化,机器人工作时间T只与走过的区间长度L有关(T=2^(L-1)),因此题目转化为:求出一个最短区间,满足如下限制:
- 区间的并集∪必须包含[1,n]所有的方格,即必须要能清扫所有方格
- 每个区间内必须至少包含一个机器人,机器人在某个区间的任意位置工作时间都是一样的,无需限定机器人一定要在区间的中点
方法一:二分查找区间
可以从分析思路中得知区间1<=L<=n,因此用二分找到此区间长度L
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
/**
*
*/
public class Main {
//下标均从1开始
static int N=100000+5;
static int[] robotIdx=new int[N];
static int n;
static int k;
public static void main(String[] args) throws IOException {
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
String[] line = reader.readLine().split(" ");
n=Integer.parseInt(line[0]);
k=Integer.parseInt(line[1]);
for (int i = 0; i < k; i++) {
line=reader.readLine().split(" ");
robotIdx[i+1]=Integer.parseInt(line[0]);
}
//左闭右开,对机器人坐标排序,因为后面需要遍历机器人
Arrays.sort(robotIdx,1,k+1);
//找到能全覆盖的最小区间
int l=1,r=n;
while (l<r) {
int mid=(l+r)>>1;
if (check(mid)) {
r=mid;
}else{
l=mid+1;
}
}
System.out.println(2*(l-1));
}
//此区间长度能扫完则返回true,否则返回false
private static boolean check(int length) {
int hasClear=0;
for (int i = 1; i <= k ; i++) {
//这个扫地机器人必须能接上上一个扫过的位置
if (robotIdx[i]-length<=hasClear) {
if (robotIdx[i]<=hasClear) {
hasClear=robotIdx[i]+length-1;
}else{
hasClear+=length;
}
}else{
//接不上
return false;
}
}
return hasClear>=n;
}
}
方法二:dfs查找区间
当区间长度为6时可能出现如下情况:
因此区间分布由两个变量决定,区间长度和第一个区间的显现的长度,从这两个出发dfs所有情况,时间复杂度约为:区间长度种类×第一个区间长度变化≈N²=1e10,可能会爆。
代码待补充。