2.管道 - 蓝桥云课 (lanqiao.cn) 这道题目的意思是,比如有如下这样一个管道: 我们拿给的测试用例举例,假设有三个阀门:
a1阀门在1时刻打开,水从阀门出来会向两边流动,每一时刻流动一个格子:
在第二时刻的时候,把a2阀门也打开,那么整个管道都会被水灌满,因此管道内的所有检测器都可以检测到水,我们的答案就是2:
我们再拿题目给的样例讲一下:
a1在第1时刻打开,水会流下来:
在第二时刻,a3这个阀门也会打开,水也会流下来:
接下来就一直流动,总共流动了4秒:
当第五时刻的时候,a2阀门打开:
此时管道被水灌满,管道内每个传感器都可以检测到水,我们就说第五秒管道内传感器都可以检测到水,因此答案是5.
思想
我们可以从1开始枚举时间,每枚举一刻时间就判断该时刻整个管道是否可以检测到水。
水是从阀门来的。
我们写一个check()函数。
函数体:用i去枚举管道内每个位置,j去枚举管道内每个阀门。
pos[]代表阀门,pos[j]-i表示水可以从阀门流到i位置。
把我们之前枚举的每一个时刻都传给check()函数,用于检查某个位置是否在某个阀门的有效范围内,从而确定管道上的每个位置是否被完全覆盖。
如果没有被覆盖,我们就把下一个时刻继续传给check()函数,直到某个时刻,确定了管道每个位置都被覆盖了,return true给主函数,break;输出该时刻。
code
#include <iostream>
using namespace std;
const int N=100100;
int s[N],pos[N];
int n,len;
bool check(int t)
{
//枚举位置
for(int i=1;i<=len;i++)
{
int ok=0;
//枚举阀门
for(int j=1;j<=n;j++)
{
//看是否满足条件
if(abs(pos[j]-i)<=t-s[j])
{
ok=1;
break;
}
}
if(ok==0)return false;
}
return true;
}
int main()
{
cin>>n>>len;//n个阀门,管道Len长度
for(int i=1;i<=n;i++)
{
cin>>pos[i]>>s[i];//输入所有阀门位置
}
int t=1;//从1开始枚举每个时刻,每个时刻都传给check()检测是否在该时刻水流满了管道
for(t=1;;t++)
if(check(t))
{
cout<<t<<endl;
return 0;
}
return 0;
}
if(abs(pos[j]-i)<=t-s[j])这句话是什么意思?比如a3阀门在第二时刻打开:
那么就必须要保证a3阀门的水要在第5时刻流到6位置:
这样才能保证在第五时刻,a2阀门打开,刚好就能把管道灌满水了:
pos[2]-6=5-2
9-6=5-2
3=3
同理,其他阀门也要满足这个条件,那么就可以满足在t时刻水灌满整个管道。这也就是我们为什么要枚举管道内的所有阀门,管道内每个位置的原因:
时间复杂度:
我们一共三层循环遍历了n,t,len
我们拿30%数据范围来算,len和t差不多长,也就是len^2*n=1e8,可以全部通过30%样例:
ps
二分优化
假设t时刻可以将水将灌满整个管道,那么t+1时刻是不是也可以。
假设t时刻不可以将水灌满整个管道,那么t-1时刻是不是也不可以。
根据这个原理我们可以用二分进行优化处理。
l,r的范围:
时间复杂度
仍然是遍历了三个元素:n,t,len。但是t是二分折半遍历的,所以说会比之前的效率稍微高一点:
代码托管: