zoukankan      html  css  js  c++  java
  • POI2006 ZAB-Frogs

    题目

    一群青蛙正在摧毁Byteotia所有的庄稼. 一个叫Byteasar的农夫决定使用一种放在田里的奇特的"scarefrogs"来吓跑他们, 所有的青蛙在跳跃过程中都尽量使自己离他们越远越好, 即是让自己离最近的scarefrog越远越好.
    Byteasar的田是块矩形的土地. 青蛙们跳跃的方向平行于坐标轴并且每次跳跃的距离为1. 一条跳跃路线的scarefrogs-距离为路径上所有点距离所有scarefrogs的最近距离.
    Byteasar已经知道青蛙们的出发位置和目的地位置, 所以他在田里放置了若干个scarefrogs. 他请求你帮忙写一个程序找一条路径使得该路径的scarefrogs-距离最大.

    题目链接

    思路

    斜率优化dp。

    首先,题目可以分成两个部分:
    第一部分:求出每个点到最近的scarefrogs的距离。
    第二部分:二分答案,bfs求出青蛙是否可以达到终点。

    主要卡在第一部分。

    先来考虑冗余的信息:单独考虑一列时,对于某一行而言,显然只有离这一列最近的那个点对这一列的答案有影响,所以实际上对答案有影响的点是很少的,不超过2000个。

    然后思考如何一下子把一行的信息都处理出来。

    先推一个式子:

    对于(a)(b)两个点和一组(x),(y)

    (b)优于(a)

    [(X_b-x)^2+(Y_b-y)^2leq(X_a-x)^2+(y_a-y)^2 ]

    将其展开:

    [frac{x_b^2-x_a^2+2x(x_a-x_b)}{y_b-y_a}+y_a+y_blt 2y ]

    观察这个式子,发现可以斜率优化。

    之后就是斜率优化裸题了,主要考验代码功底。

    代码

    #include<bits/stdc++.h>
    #define M 1005
    #define LL long long
    using namespace std;
    int n,m,sx,sy,ex,ey,t,top,l;
    int dxy[4][2]={1,0,0,1,-1,0,0,-1};
    LL  G[M][M];
    bool vis[M][M]; 
    struct node{LL x,y;}stk[M],A[M];
    vector<int>wk[M];
    bool check(int x,int y){
        return x>=1&&x<=n&&y>=1&&y<=m&&!vis[x][y];
    }
    double get(node B,node A,LL x){
        return 1.0*(B.x*B.x-A.x*A.x+2*x*(A.x-B.x))/(B.y-A.y)+A.y+B.y;
    }
    void Init(){
        for(int i=1;i<=m;i++)sort(wk[i].begin(),wk[i].end());
        for(int i=1;i<=n;i++){
            top=l=0;
            for(int j=1;j<=m;j++){
                int len=wk[j].size();
                if(!len)continue;
                int t=lower_bound(wk[j].begin(),wk[j].end(),i)-wk[j].begin()-1;
                if(t==-1||(t<len-1&&i-wk[j][t]>wk[j][t+1]-i))t++;
                A[++l]=(node){wk[j][t],j};
            }
            for(int j=1;j<=l;j++){
                while(top>1&&get(A[j],stk[top],i)<=get(stk[top],stk[top-1],i))top--;
                if(top<=1||get(A[j],stk[top],i)>get(stk[top],stk[top-1],i))stk[++top]=A[j];   
            }
            for(int j=m;j>=1;j--){
                while(top>1&&get(stk[top],stk[top-1],i)>2*j)top--;
                G[i][j]=1LL*(i-stk[top].x)*(i-stk[top].x)+1LL*(j-stk[top].y)*(j-stk[top].y);
            }
        }
    }
    queue<node>Q;
    bool bfs(int lim){
        memset(vis,0,sizeof(vis));
        while(!Q.empty())Q.pop();
        Q.push((node){sx,sy});vis[sx][sy]=1;
        if(G[sx][sy]<lim)return 0;
        while(!Q.empty()){
            node e=Q.front();Q.pop();
            if(e.x==ex&&e.y==ey)return 1;
            for(int i=0;i<4;i++){
                int nx=e.x+dxy[i][0];
                int ny=e.y+dxy[i][1];
                if(check(nx,ny)&&G[nx][ny]>=lim){
                    vis[nx][ny]=1;
                    Q.push((node){nx,ny});
                }
            }
        }
        return 0;
    }
    int main(){
        scanf("%d%d%d%d%d%d%d",&n,&m,&sx,&sy,&ex,&ey,&t);
        for(int i=1,x,y;i<=t;i++){
            scanf("%d%d",&x,&y);
            wk[y].push_back(x);
        }
        Init();
        int l=0,r=0,ans=0;
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
                r=max(r,(int)G[i][j]);
        while(l<=r){
            int mid=(l+r)>>1;
            if(bfs(mid)){
                ans=mid;
                l=mid+1;
            }
            else r=mid-1;
        }
        printf("%d
    ",ans);
        return 0;
    } 
    
  • 相关阅读:
    vue-cli3.0
    windows服务器的误解
    redis实现消息队列-java代码实现
    Docker 修改容器内的时区
    Spring boot项目分环境Maven打包,动态配置文件,动态配置项目
    rsa公钥和私钥到底哪个才是用来加密,哪个用来解密?
    session和cookie的区别和联系详解,Cookie Session相关看这篇就够了。
    面试中的nginx高可用高并发!
    js正则表达式验证、匹配数字、匹配字符串、匹配中文、匹配任意字符备忘录
    thymeleaf模板、thymeleaf语法相关中文文档教程
  • 原文地址:https://www.cnblogs.com/zryabc/p/11202131.html
Copyright © 2011-2022 走看看