信号

信号

n 个房子排成一排,从左到右依次编号为 1n

其中一些房子内装有无线信号发射器。

这些信号发射器的有效覆盖半径为 r

更准确地说,如果第 p 号房子内装有信号发射器,则所有房间编号在 [pr+1,p+r1] 范围内的房子均可被其发出的无线信号覆盖,而其余房子则不会被其发出的无线信号覆盖。

例如,假设 n=6,r=2,且第 25 号房子内装有信号发射器,则第 2 号房子内的发射器发出的信号可以覆盖第 13 号房子,第 5 号房子内的发射器发出的信号可以覆盖第 46 号房子,将两个发射器全部打开,则无线信号可以覆盖到所有房子。

初始时,所有无线信号发射器都是关闭的,请计算至少开启多少个无线信号发射器,才能保证所有房子都被无线信号覆盖到。

输入格式

第一行包含两个整数 nr

第二行包含 n 个整数 a1,a2,,an,每个数要么是 1,要么是 0ai=1 表示第 i 号房子内装有无线信号发射器,ai=0 表示第 i 号房子内未装无线信号发射器。

输出格式

一个整数,表示需要开启的无线信号发射器的最少数量。

如果无法使得所有房子都被无线信号覆盖到,则输出 1

数据范围

6 个测试点满足 1n10
所有测试点满足 1n,r10000ai1

输入样例1:

6 2
0 1 1 0 0 1

输出样例1:

3

输入样例2:

5 3
1 0 0 0 1

输出样例2:

2

输入样例3:

5 10
0 0 0 0 0

输出样例3:

-1

输入样例4:

10 3
0 0 1 1 0 1 0 0 0 1

输出样例4:

3

 

解题思路

  假设有两个信号发射器,一个比较靠前,一个比较靠后,并且两个信号发生器都可以覆盖到最左边的那个房子,即第1个房子。

  我们考虑一下应该选择哪个发生器。可以把所有的方案(最终答案的方案)分成两类,第一类是选择靠前的发生器的方案,第二类是选择靠后的发生器的方案。我们任取第一类中的方案,且这个方案可以覆盖所有的房子,我们把靠左的那个发生器换成靠右的发生器,仍然是一个合法的方案:

  而且需要的发生器的数量是相同的,所以对于第一类中的方案,我们都可以在第二类中找到一个方案,使得这个方案所需要的发生器不比第一类的方案多。所以第二类中的方案都不比第一类的方案差,因此第二类方案中必然存在最优解(第一类方案也可能存在最优解),所以我们只需要考虑第二类的方案就可以了,即应该选择靠后的那个发生器。

  以此类推,在能够覆盖到最左边那个还没被覆盖的房子的条件下,每次都应该选择尽可能靠后的房子。

  这题贪心的模型可以参考这个模板题:区间覆盖

  AC代码如下:

复制代码
 1 #include <cstdio>
 2 #include <algorithm>
 3 using namespace std;
 4 
 5 const int N = 1010;
 6 
 7 int a[N], sz;
 8 
 9 int main() {
10     int n, m;
11     scanf("%d %d", &n, &m);
12     for (int i = 1; i <= n; i++) {
13         int val;
14         scanf("%d", &val);
15         if (val) a[sz++] = i;   // 记录有发生器的房间
16     }
17     
18     int ret = 0, last = 0;  // last表示上一个被覆盖的房间,因此还没被覆盖的房间是last+1
19     for (int i = 0; i < sz; i++) {
20         if (last >= n) break;   // 所有的房间已被覆盖
21         // 第a[i]个房间最左边能够覆盖到的房间为a[i]-m+1,如果a[i]-m+1 > last+1,表明不能够覆盖到上一个未覆盖到的房间
22         if (a[i] - m > last) break;
23         
24         int j = i;  // 在能够覆盖last+1这个房间的前提下,寻找最靠右的房间
25         while (j + 1 < sz && a[j + 1] - m <= last) {
26             j++;
27         }
28         last = a[j] + m - 1;    // 更新last
29         i = j;
30         ret++;
31     }
32     
33     printf("%d", last >= n ? ret : -1);
34     
35     return 0;
36 }
复制代码

  这题还可以用动态规划来做。

  AC代码如下,时间复杂度是O(n×m)

复制代码
 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 using namespace std;
 5 
 6 const int N = 1010;
 7 
 8 int a[N], f[N];
 9 
10 int main() {
11     int n, m;
12     scanf("%d %d", &n, &m);
13     for (int i = 1; i <= n; i++) {
14         scanf("%d", a + i);
15     }
16     
17     memset(f, 0x3f, sizeof(f));
18     for (int i = 1; i <= m; i++) {  // 初始化一开始能够覆盖到第1个房间的发射器
19         if (a[i]) f[i] = 1;
20     }
21     for (int i = 1; i <= n; i++) {
22         if (a[i]) {
23             for (int j = max(1, i - 2 * m + 1); j < i; j++) {   // 注意j可能会小于0越界
24                 if (a[j]) f[i] = min(f[i], f[j] + 1);
25             }
26         }
27     }
28     
29     int ret = N;
30     for (int i = max(1, n - m + 1); i <= n; i++) {  // 枚举能够覆盖到第n个房间的最后一个发射器
31         if (a[i]) ret = min(ret, f[i]);
32     }
33     printf("%d", ret == N ? -1 : ret);
34     
35     return 0;
36 }
复制代码

  可以用单调队列优化到O(n),AC代码如下:

复制代码
 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 const int N = 1010;
 5 
 6 int a[N], f[N];
 7 int q[N], hh, tt = -1;
 8 
 9 int main() {
10     int n, m;
11     scanf("%d %d", &n, &m);
12     for (int i = 1; i <= n; i++) {
13         scanf("%d", a + i);
14     }
15     
16     memset(f, 0x3f, sizeof(f));
17     for (int i = 1; i <= m; i++) {
18         if (a[i]) f[i] = 1;
19     }
20     for (int i = 1; i <= n; i++) {
21         if (a[i]) {
22             while (hh <= tt && q[hh] + m - 1 < i - m) {
23                 hh++;
24             }
25             if (hh <= tt) f[i] = min(f[i], f[q[hh]] + 1);
26             while (hh <= tt && f[q[tt]] >= f[i]) {
27                 tt--;
28             }
29             q[++tt] = i;
30         }
31     }
32     
33     int ret = n + 1;
34     for (int i = max(1, n - m + 1); i <= n; i++) {
35         if (a[i]) ret = min(ret, f[i]);
36     }
37     printf("%d", ret == n + 1 ? -1 : ret);
38     
39     return 0;
40
复制代码

 

参考资料

  AcWing 4421. 信号(AcWing杯 - 周赛):https://www.acwing.com/video/3871/

posted @   onlyblues  阅读(246)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效
Web Analytics
点击右上角即可分享
微信分享提示