扫地机器人(第十届蓝桥杯研究生组)

问题描述

如图,在一块长为N的方格地板上,放置K个扫地机器人(图中黑点),每个机器人都可以左右移动,且互不干扰,扫完地后又都回到原位置,为公平起见,每个机器人的工作量尽可能相同,求移动步数最多的机器人移动的步数。(题目大概是这个意思,欢迎来更正)
在这里插入图片描述
输入格式:
第一行输入两个整数:N、K
第二行输入K个整数,表示扫地机器人的位置
输出格式:
输出一个整数,表示移动步数最多的机器人移动的步数
案例:
输入:
10 3
3 5 8
输出:
6
说明:
总移动步数最少的方案为:
1号机器人路线:3->2->1->2->3->4->3
2号机器人路线:5->6->7->6->5
3号机器人路线:8->9->10->9->8

方法一

算法思想
假设每个机器人的位置为a[i],对应扫地区间为[xi,yi](i=1,2,…,K),显然x1<=a[i]<=yi。于是,问题转化为:寻找一组区间(K个),在区间长度尽可能一致的情况下,使这组区间能够覆盖满1~N,并且每个区间内至少有一个机器人(否则至少有一个区间内没有机器人,即该区间没有机器人扫,无意义)。设最长的区间长度为L,则移动步数最多的机器人移动了2*(L-1)步。
在不影响最长区间长度的情况下,为方便计算,不妨设每个区间的长度都为L。显然,N/K<=L<=N。为方便读者理解笔者思路,下面给出几个特例图。
在这里插入图片描述
算法步骤

  • 1 将机器人的位置a[ ]在方格b[ ]中标记,并对a[ ]排序
  • 2 将方格划分成若干个区间D1,D2,…,Dm,满足:
    在这里插入图片描述
  • 3 对L从N/K到N,first_L从L到1开始遍历,直到找到一个L和first_L满足在每个区间内至少有一个机器人,输出L并结束程序。

说明:

  1. 之所以要改变第1个区间的长度,因为会出现如下情况:
    在这里插入图片描述
    当区间长度L=6时,系统会误判区间长度不够。实际上,L=6够了,如下:
    在这里插入图片描述
  2. 之所以只改变第1个区间的长度,因为区间之间是紧挨着的,缩小第1个区间的长度,后面的区间都会向左平移,其实第1个区间也向左平移了,只是前一部分越界了没显示。
    算法实现
#include<iostream>
#include<algorithm>
using namespace std;
int N,K;
int a[100]; //K个机器人位置
int b[100]; //标记N个方格中是否有机器人 
int check1(int first_L,int L){ //第一个区间长度为first_L,之后区间长度都为L 
	int i,j;
	if(first_L+(K-1)*L<N){
		return 0;
	}
	i=1; //第i个区间 
	j=1; //当前查看的方格位置 
	while(j<=N){
		if(b[j]==1){ //第i个区间内有机器人 
			j=first_L+(i-1)*L+1; //j指向下一个区间起点 
			i++; //下一个区间 
		}else{
			j++;
			if(j==first_L+(i-1)*L+1||j==N+1){ //第i个区间内没有机器人
				return 0; 
			}
		}		
	} 
	return 1;
} 
int check(int L){
	int first_L; //首区间的长度(取值范围:1~L) 
	for(first_L=L;first_L>0;first_L--){
		if(check1(first_L,L)){
			return 1;
		}
	}
	return 0;
}
int fun(){
	int i,j,L;
	for(L=N/K;L<=N;L++){ 
		if(check(L)){
			return L;
		}
	}
} 
int main(){
	int i,L;
	cin>>N>>K;
	for(i=1;i<=K;i++){
		cin>>a[i];
		b[a[i]]=1; //标记a[i]位置有机器人 
	}
	sort(a+1,a+K+1);
	L=fun();
	cout<<2*(L-1);
	return 0;
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
算法思想的正确性还有待考证,欢迎热心的读者批评指正!

方法二

算法思想
如果每个机器人的活动区间确定了,其最大的移动步数可根据2*(L-1)求得。为减轻每个机器人的任务,限制相邻的机器人的活动范围不相交。

第1个机器人的活动范围:1~a[2]-1,其右边界活动范围:a[1] ~ a[2]-1;
第2个机器人的活动范围:a[1]+1~a[3]-1,其右边界活动范围:a[2] ~ a[3]-1;
第3个机器人的活动范围:a[2]+1~a[4]-1,其右边界活动范围:a[3] ~ a[4]-1;

第K-1个机器人的活动范围:a[K-2]+1~a[K]-1,其右边界活动范围:a[K-1] ~ a[K]-1;
第K个机器人的活动范围:a[K-1]+1~N,其右边界活动范围:N ~ N;

第1个机器人的左边界已确定,如果其右边界确定了,第二个机器人的左边界就确定了,即后面的机器人的左边界依赖于前面机器人的右边界,由此可用dfs对每个机器人的右边界的所有情况进行遍历,每找到一种区间划分法,检验是否优于当前解

算法实现

#include<iostream>
#include<algorithm>
#define INF 10000000 
using namespace std;
struct neighbor{ //机器人活动范围
	int l; //左边界
	int r; //右边界
};
int N,K;
int a[100]; //K个机器人位置
neighbor B[100]; //K个机器人的最大移动邻域
neighbor F[100]; //K个机器人的移动邻域
int min_max_L=INF; //最小的最大邻域长度
void init(){ //初始化函数 
	int i;
	cin>>N>>K;
	for(i=1;i<=K;i++){
		cin>>a[i];
	}
	sort(a+1,a+K+1);
	B[1].l=1;
	B[K].r=N;
	if(K==1){
		B[1].r=N;
	}else{
		B[1].r=a[2]-1;
		B[K].l=a[K-1]+1;
	}
	for(i=2;i<K;i++){
		B[i].l=a[i-1]+1;
		B[i].r=a[i+1]-1;
	}
	F[1].l=1; //第1格一定由第1个机器人扫 
	F[K].r=N; //第N格一定由第K个机器人扫
}
int max_L(){ //最大区间长度 
	int i,L,m=-INF;
	for(i=1;i<=K;i++){
		L=F[i].r-F[i].l+1;
		if(L>m){
			m=L;
		}
	}
	return m; 
}
void search(int index,int left){ //第index个机器人,其左边界为left
	int i,L;
	F[index].l=left; //第index个机器人的左边界
	if(index==K){
		L=max_L();
		if(L<min_max_L){
			min_max_L=L;
		}
		return;
	}
	for(i=a[index];i<=B[index].r;i++){
		F[index].r=i; //第index个机器人的右边界
		search(index+1,i+1);
	}
} 
int main(){
	int i,L;
	init(); //初始化 
	search(1,1);
	cout<<2*(min_max_L-1);
	return 0;
}
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

little_fat_sheep

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值