滴滴 秋招 2023.09.15 编程题目与题解

1、照明灯安装

你负责在一条笔直的道路上安装一些照明灯。但是道路上并不是任意位置都适合安装照明灯,具体地,假设将道路看作一条起点坐标为\(0\),终点坐标为\(M\)的线段,那么只有在\(x_1,x_2,..,x_n\)\(n\)个坐标可以安装照明灯,且每个坐标上最多只能安装一个照明灯。现在你要在道路上安装\(k\)个照明灯,为了使照明灯能够尽量覆盖道路,你需要使距离最近的两个照明灯尽量远。请问这个最近距离最大可以是多少?

输入

第一行是两个整数\(n,k\),分别表示可以安装照明灯的位置数和需要安装的照明灯数量。

接下来一行\(n\)个整数\(x_1,x_2,\dots,x_n\)表示可以安装照明灯的坐标。保证 \(x_1<x_2<\dots<x_n\)

  • \(1<k\le n\le 100000, 1\le x_i\le 1000000\)

输出

一行,一个整数,表示最近距离的最大值。

样例

1
2
3
4
5
6
7
8
9
10
11
输入:
5 3
1 3 4 7 9

输出:
3

提示:
分别放在1、4、7的位置(放在1、4、9也可以)
能够证明3是最小的最大距离。

解答

本题是经典二分。二分判断最大距离是\(x\),如果一个路灯距离上一个路灯的距离超过\(x\),那么当前路灯可以进行安装。为了方便,在安装第一盏路灯前,可以假设上一路灯的距离为\(-\infty\)

最终只需要判断能安装路灯的数量是否超过\(k\)即可。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# include <bits/stdc++.h>
using namespace std;

const int N=100004;
int a[N],n,k;
bool ok(int x){
int pre=-1e9,cnt=0;
for(int i=1;i<=n;i++){
if(a[i]-pre>=x){
++cnt;pre=a[i];
}
}
return cnt>=k;
}
int main(){
scanf("%d %d",&n,&k);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
int l=0,r=1e6+4;
while(l<r){
int mid=(l+r+1)>>1;
if(ok(mid)) l=mid;
else r=mid-1;
}
printf("%d\n",l);
}

2、黑白块

有一个\(n*m\)的网格图,起初你在\((1,1)\)处,现在想走到\((n,m)\)处,且经过的黑色网格尽可能少。请输出最少需要经过多少个黑色网格。网格图是四联通的,也就是每次只能向上下左右四个相邻的格子移动,且不能走出边界。

输入

第一行两个正整数\(n\)\(m\),含义如上文所述。

接下来\(n\)行,每行\(m\)个数,此数为\(1\)时表示为黑色格子,为\(0\)时表示为白色格子

  • \(1\le n\times m\le 100000\)

输出

输出仅包含一个非负整数,表示答案。

样例

1
2
3
4
5
6
7
8
9
10
输入:
5 3
0 1 0
0 1 1
0 1 0
1 0 0
1 0 0

输出:
1

解答

这道题是一道经典的0-1BFS题目。对于每个格子,我们可以从其到相邻的格子连一条边。如果最终到达的格子是黑格子,那么边权为\(1\),否则边权为\(0\)

我们使用双端队列来实现这个0-1BFS问题。假设当前走到了一个白格子,那么花费数不变,并将状态从左端插入队列;否则花费数增加\(1\),从有端插入队列。

最终搜索完成后,得到的就是从格子\((1,1)\)到达棋盘上所有其它格子的最少经过的黑色格子数量,我们只需要返回位于\((n,m)\)的那个即可。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# include <bits/stdc++.h>
using namespace std;
struct P{
int x,y,l;
};
int dx[4]={-1,1,0,0},dy[4]={0,0,-1,1};
int main(){
int n,m;
scanf("%d %d",&n,&m);
vector<vector<int>>a(n,vector<int>(m));
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
scanf("%d",&a[i][j]);
vector<vector<int>>f(n,vector<int>(m,-1));
deque<P>q;
q.push_back(P{0,0,a[0][0]});
while(!q.empty()){
P u=q.front();q.pop_front();
if(f[u.x][u.y]!=-1) continue;
f[u.x][u.y]=u.l;
for(int i=0;i<4;i++){
int x=u.x+dx[i],y=u.y+dy[i];
if(x<0||y<0||x>=n||y>=m||f[x][y]!=-1) continue;
if(a[x][y]==0) q.push_front(P{x,y,u.l});
else q.push_back(P{x,y,u.l+1});
}
}
printf("%d\n",f[n-1][m-1]);
}

如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
Ujimatsu Chiya 微信 微信
Ujimatsu Chiya 支付宝 支付宝