水果忍者(找一条穿过所有线的线 思维)

原题: https://pintia.cn/problem-sets/994805046380707840/problems/994805049102811136

题意:

有n条竖线,给出位置和长度,你需要找出一条线,穿过所有的线(包括边界点)。要求线的两个顶点坐标为整数。

方法一:

三分在-1e6上的可行区域,check函数为:从这个点投出光,穿过每条线段后可能会遮挡一部分,判断是否有一丝光穿过所有线段。复杂度 O ( N l o g N ) O(NlogN)

但是找到这个区域后找两个整数点就比较麻烦了。

方法二:

发现不管怎么画,都可以通过微调答案线使之穿过至少一个上端点,一个下端点。所以我枚举每个上端点作为答案端点。

显然,对于引伸出的线,所有上端点都应该在其上方,所有下端点都在其下方。

  1. 为了使所有上端点在上面,对于左边的上端点,左边要往下压(类似于跷跷板),那么斜率越来越大;
  2. 对于右边的上端点,右边往下压,斜率越来越小;此时判断斜率是否小于左边的最大斜率,如果是,则说明不存在经过当前点的线,使所有点在其上方。
  3. 下端点类似,只不过左边往上斜率越来越小,右边往上斜率越来越大。

结束之后有:

  1. 任意满足比左上大,比右上小的斜率k,都可以使全部上端点处于上方;
  2. 比右下大,左下小的,所有下端点处于其下方;
  3. 此时若有一个k同时满足这两个条件,就是答案。

复杂度 O ( N 2 ) O(N^2)

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e4+4;
struct node{
    float x,Y,y;
    bool operator<(const node &r)const{
        return x<r.x;
    }
}e[maxn];

int main(){
    int n;scanf("%d",&n);
    for(register int i=1;i<=n;i++)
        scanf("%f%f%f",&e[i].x,&e[i].Y,&e[i].y);
    if(n==1){
        return 0*printf("%.0f %.0f %.0f %.0f\n",e[1].x,e[1].Y,e[1].x+1,e[1].Y);
    }

    sort(e+1,e+1+n);
    for(register int i=1;i<=n;i++){
        float upl=-1e9,upr=1e9,downl=1e9,downr=-1e9;
        int p1=-1,p2=-1,p3=-1,p4=-1;
        int can=1;
        for(register int j=1;j<i;j++){
            if(upl<(e[i].Y-e[j].Y)/(e[i].x-e[j].x))
                upl=(e[i].Y-e[j].Y)/(e[i].x-e[j].x),p1=j;
        }
        for(register int j=i+1;j<=n;j++){
            if(upr>(e[i].Y-e[j].Y)/(e[i].x-e[j].x)){
                upr=(e[i].Y-e[j].Y)/(e[i].x-e[j].x),p2=j;
                if(upr<upl)
                    {can=0;break;}
            }
        }
        if(!can)continue;
        for(register int j=1;j<i;j++){
            if(downl>(e[i].Y-e[j].y)/(e[i].x-e[j].x))
                downl=(e[i].Y-e[j].y)/(e[i].x-e[j].x),p3=j;
        }
        for(register int j=i+1;j<=n;j++){
            if(downr<(e[i].Y-e[j].y)/(e[i].x-e[j].x)){
                downr=(e[i].Y-e[j].y)/(e[i].x-e[j].x),p4=j;
                if(downr>downl)
                    {can=0;break;}
            }
        }
        if(!can)continue;
        if(downl>=upr&&upr>=downr&&p2>0){
            return 0*printf("%.0f %.0f %.0f %.0f\n",e[i].x,e[i].Y,e[p2].x,e[p2].Y);
        }
        else if(downl>=upl&&downl<=upr&&p3>0){
            return 0*printf("%.0f %.0f %.0f %.0f\n",e[i].x,e[i].Y,e[p3].x,e[p3].y);
        }
        else if(downr>=upl&&downr<=upr&&p4>0){
            return 0*printf("%.0f %.0f %.0f %.0f\n",e[i].x,e[i].Y,e[p4].x,e[p4].y);
        }
        else if(upl>=downr&&upl<=downl&&p1>0){
            return 0*printf("%.0f %.0f %.0f %.0f\n",e[i].x,e[i].Y,e[p1].x,e[p1].Y);
        }
    }
}

猜你喜欢

转载自blog.csdn.net/jk_chen_acmer/article/details/88854419