扫地机器人
题目描述
小明公司的办公区有一条长长的走廊,由 N 个方格区域组成,如下图所示。
走廊内部署了 K 台扫地机器人,其中第 i 台在第 Ai 个方格区域中。已知扫地机器人每分钟可以移动到左右相邻的方格中,并将该区域清扫干净。
请你编写一个程序,计算每台机器人的清扫路线,使得
它们最终都返回出发方格,
每个方格区域都至少被清扫一遍,
从机器人开始行动到最后一台机器人归位花费的时间最少。
注意多台机器人可以同时清扫同一方块区域,它们不会互相影响。
输出最少花费的时间。 在上图所示的例子中,最少花费时间是 6。第一台路线: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≤105,1≤Ai≤N。
输出描述
输出一个整数表示答案。
输入样例
10 3
5
2
10
输出样例
6
解题思路
本题为一道比较明显的二分题目。
题目要求最少花费时间。由于每个机器人的工作时间可能不同,那么这些机器人各自的花费时间中的最大值(设为 t )的就是本题要求的答案, 需要做的是使得 t 最小。将最大花费时间(t)最小化,显然需要使用二分求解。 假设某个机器人需要清扫 a,b,c,d 四个格子,因为这个机器人清扫完还需要回到最初始的位置,所以无论这个机器人初始位置在什么地方, 其清扫路径的本质都是重复两次 a 到 b,b 到 c,c 到 d 的过程,花费时间为 6,由此,假设某个机器人清扫的格子范围为 len, 那么这个机器人花费的时间为 (len-1)*2。所以只需要对机器人清扫的范围(len)进行二分即可,最后的答案为 t=(len-1)*2。 显然当每个机器人清扫的范围大小相同时,花费时间最小。 可以对清扫范围进行二分,然后验证其答案的正确性即可,判断条件是清扫范围可以使得每个格子都能够扫到 可以明显的知道,最左边的格子由左边第一台机器人清扫,花费时间是最少的,在此可以采用贪心的思想, 让每台机器人都要优先清扫其左边还未扫的到格子,然后再往右扫,在二分得到的范围下往右扫得越多越好, 这样可以减少右边下一个机器人需要往左扫的范围,增加其往右扫的范围,以此类推,可减少清扫时间。
综上,本题采用二分加贪心的思想解答。
代码
#include<bits/stdc++.h>
using namespace std;
int robot[1000005]; //机器人位置
int n,k;
int check(int len){
int step=0; //step代表清扫到了哪个位置
for(int i=0;i<k;i++){
if(robot[i]-len<=step){ //如果当前机器人只扫左侧,能够覆盖左侧未清扫的位置,则可进行当前机器人的清扫
if(robot[i]<=step) //如果当前机器人已经处于清扫过的位置,则当前机器人只扫右侧区域
step=robot[i]+len-1;
else //否则从上一个清扫到的位置继续
step+=len;
}
else //当前机器人只扫左侧,不能覆盖左侧未清扫的位置,当前方案不可行,返回
return 0;
}
if(step>=n) //表示当前方案可行
return 1;
else //表示当前方案不可行
return 0;
}
int main(){
int cnt;
scanf("%d %d",&n,&k);
for(int i=0;i<k;i++)
scanf("%d",&robot[i]);
sort(robot,robot+k); //首先对机器人的位置进行排序
int l=0,r=n;
while(l<=r){
int mid=(l+r)/2;
if(check(mid)){ //如果当前方案可行,则缩小清扫范围,试图寻找更小的方案
r=mid-1;
cnt=mid;
}
else //如果方案不可行,则扩大清扫范围,寻找可行方案
l=mid+1;
}
printf("%d",(cnt-1)*2);
return 0;
}