首页 > 试题广场 >

谁挡住了我的红绿灯

[编程题]谁挡住了我的红绿灯
  • 热度指数:1049 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 256M,其他语言512M
  • 算法知识视频讲解

命运的十字路口前,有辆车在等红灯。还来不及思考此刻的选择会将他们带向何方,司机们发现了一个更现实的问题——由于车的高度不尽相同,某些车会因前车的遮挡而无法看到红绿灯。这时候,“谁挡住了谁的红绿灯”便成为一个……很好的笔试题!


现已知红绿灯高度为辆按距离红绿灯由近到远分别标号为,第辆车与红绿灯的距离为,高度为。为简化问题,我们以距红绿灯的距离为x轴,高度为y轴建立平面直角坐标系,则红绿灯可抽象为一点,第辆车可抽象为线段。我们称车挡住了车的红绿灯,当且仅当,且车看红绿灯的视线,即的连线与代表车的线段相交(含两端)。

现在,我们需要你对每辆车计算谁挡住了它的红绿灯;即对于每一辆车,求最大的满足“车挡住了车的红绿灯”。

输入描述:
第一行包含两个非负整数
第二行包含个非负整数


输出描述:
输出共有行,第行包含对于车的答案,若没有车挡住车,则该行输出0。
示例1

输入

9 5
5 4 3 4 3 3 3 3 3

输出

0
1
2
1
4
4
4
4
1

备注:

20%的数据 
50%的数据 
80%的数据 
100%的数据 

单调栈

思路并不难想,用单调栈来做,可以理解为构建一个“小压大”的单调栈。栈不为空,且当前元素直接压入会破坏单调性时(栈顶车辆不会挡住当前车辆的视线)进行弹栈。

那么如何判断车辆会遮挡车辆的视线呢?需要一些数学方法。

根据上图,我们可以计算得到的连线方程,然后我们把代入方程,如果得到的值没有超过,即,就说明车辆会遮挡车辆的视线。注意在计算时把除法判断转换为等效的乘法判断,防止浮点数不精确可能会产生影响,并将整型转长整型防止溢出。
import java.io.*;
import java.util.*;
public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        String[] params = br.readLine().split(" ");
        int n = Integer.parseInt(params[0]);
        int h = Integer.parseInt(params[1]);
        params = br.readLine().split(" ");
        int[] heights = new int[n + 1];
        heights[0] = h;
        for(int i = 0; i < n; i++){
            heights[i + 1] = Integer.parseInt(params[i]);
        }
        int[] res = new int[n + 1];
        Stack stack = new Stack();
        for(int i = 1; i <= n; i++){
            while(!stack.isEmpty() && check(stack, heights, i, h)){
                int top = stack.pop();
                res[top] = stack.isEmpty()? 0: stack.peek();
            }
            stack.push(i);
        }
        while(!stack.isEmpty()){
            res[stack.pop()] = stack.isEmpty()? 0: stack.peek();
        }
        for(int i = 1; i <= n; i++){
            System.out.println(res[i]);
        }
    }

    private static boolean check(Stack stack, int[] heights, int i, int h) {
        int j = stack.peek();
        return (long)i * heights[j] < (heights[i] - h) * (long)j + (long)h*i;
    }
}

讲道理已经是O(N)的时间复杂度了,但一直过不了。这个题卡时间卡得有点无语,改成C++还会卡打印API的时间,离离原上谱,知道思路就好了吧。

编辑于 2022-04-20 17:51:01 回复(0)