蓝桥杯 2.管道

57 阅读3分钟

2.管道 - 蓝桥云课 (lanqiao.cn) 这道题目的意思是,比如有如下这样一个管道: 我们拿给的测试用例举例,假设有三个阀门:

image.png

a1阀门在1时刻打开,水从阀门出来会向两边流动,每一时刻流动一个格子:

image.png 在第二时刻的时候,把a2阀门也打开,那么整个管道都会被水灌满,因此管道内的所有检测器都可以检测到水,我们的答案就是2:

image.png

我们再拿题目给的样例讲一下: image.png

a1在第1时刻打开,水会流下来:

image.png

在第二时刻,a3这个阀门也会打开,水也会流下来:

image.png

接下来就一直流动,总共流动了4秒:

image.png

当第五时刻的时候,a2阀门打开:

image.png

此时管道被水灌满,管道内每个传感器都可以检测到水,我们就说第五秒管道内传感器都可以检测到水,因此答案是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阀门在第二时刻打开:

image.png 那么就必须要保证a3阀门的水要在第5时刻流到6位置:

这样才能保证在第五时刻,a2阀门打开,刚好就能把管道灌满水了:

image.png

pos[2]-6=5-2
9-6=5-2
3=3

同理,其他阀门也要满足这个条件,那么就可以满足在t时刻水灌满整个管道。这也就是我们为什么要枚举管道内的所有阀门,管道内每个位置的原因:image.png

时间复杂度:

我们一共三层循环遍历了n,t,len

我们拿30%数据范围来算,len和t差不多长,也就是len^2*n=1e8,可以全部通过30%样例:

image.png

image.png

ps

image.png

二分优化

假设t时刻可以将水将灌满整个管道,那么t+1时刻是不是也可以

假设t时刻不可以将水灌满整个管道,那么t-1时刻是不是也不可以

根据这个原理我们可以用二分进行优化处理。

image.png

l,r的范围:

image.png

时间复杂度

仍然是遍历了三个元素:n,t,len。但是t是二分折半遍历的,所以说会比之前的效率稍微高一点:

image.png

代码托管: