zoukankan      html  css  js  c++  java
  • water 解题报告

    water

    题目描述

    有一块矩形土地被划分成(n imes m)个正方形小块。这些小块高低不平,每一小块都有自己的高度。水流可以由任意一块地流向周围四个方向的四块地中,但是不能直接流入对角相连的小块中。

    一场大雨后,由于地势高低不同,许多地方都积存了不少降水。

    给定每个小块的高度,求每个小块的积水高度。

    注意:假设矩形地外围无限大且高度为(0)

    输入输出格式

    输入格式

    第一行包含两个非负整数(n,m)

    接下来(n)行每行(m)个整数表示第(i)行第(j)列的小块的高度。

    输出格式

    输出(n)行,每行(m)个由空格隔开的非负整数,表示每个小块的积水高度。

    说明:

    对于(20\%)的数据(n,mle 4)

    对于(40\%)的数据(n,mle 15)

    对于(60\%)的数据(n,mle 50)

    对于(100\%)的数据(n,mle 300),|小块高度|(le 10^9)
    在每一部分数据中,均有一半数据保证小块高度非负


    有一种堆+遍历低点的做法,不太懂具体的复杂度,没写。

    考虑一个点的边界最低点一定是从它出去到矩形外的每条四联通路径边权的最大值中的最小值。

    把相邻两个块连边,权值为(max height)

    这个东西可以把最小生成树求出来,然后就是询问树上两点间距离的最大值了。

    发现有一个点是确定的,就是矩形外抽象的那个点。

    为什么可以求最小生成树呢?其实货车运输那个题和这个差不多。

    考虑某两个点有(n)条路径,现在把它们每条路径的最大值断开,这时候再保证联通,连上的就是最小的最大值了。


    Code:

    #include <cstdio>
    #include <algorithm>
    const int N=1e5;
    int n,m,h[N],f[N],ans[N],tot;
    int cal(int i,int j)
    {
        if(i==n+1||j==m+1||i==0||j==0) return 0;
        return (i-1)*m+j;
    }
    struct node
    {
        int u,v,w;
        bool friend operator <(node n1,node n2){return n1.w<n2.w;}
    }e[N<<2];
    int Next[N<<1],to[N<<1],edge[N<<1],head[N],cnt;
    void add(int u,int v,int w)
    {
        to[++cnt]=v,edge[cnt]=w,Next[cnt]=head[u],head[u]=cnt;
    }
    int max(int x,int y){return x>y?x:y;}
    int Find(int x){return f[x]=f[x]==x?x:Find(f[x]);}
    void Merge(int x,int y){f[Find(x)]=Find(y);}
    void krus()
    {
        for(int i=0;i<=m*n;i++) f[i]=i;
        std::sort(e+1,e+1+tot);
        for(int i=1;i<=tot;i++)
        {
            int u=e[i].u,v=e[i].v,w=e[i].w;
            if(Find(u)!=Find(v)) Merge(u,v),add(u,v,w),add(v,u,w);
        }
    }
    void dfs(int now,int fa)
    {
        for(int i=head[now];i;i=Next[i])
        {
            int v=to[i],w=edge[i];
            if(v!=fa)
                ans[v]=max(ans[now],w),dfs(v,now);
        }
    }
    const int dx[5]={0,-1,0,1,0};
    const int dy[5]={0,0,1,0,-1};
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
                scanf("%d",h+cal(i,j));
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
            {
                int u=cal(i,j);
                for(int k=1;k<=4;k++)
                {
                    int v=cal(i+dx[k],j+dy[k]);
                    e[++tot]={u,v,max(h[u],h[v])};
                }
            }
        krus();
        dfs(0,0);
        for(int i=1;i<=n*m;i++)
        {
            printf("%d ",ans[i]-h[i]);
            if(i%m==0) printf("
    ");
        }
        return 0;
    }
    
    

    2018.10.15

  • 相关阅读:
    使用VisualStudio2015开发QT项目
    界面控件
    SmartGit 试用过期
    视图和模型变换
    模型变换和视图变换
    一元二次方程
    论cudnn与cuda之间的关系,和实际例子测试。
    在Ubuntu 18.04上安装Tensorflow
    ubuntu14.04安装CUDA8.0
    Windows10系统远程桌面连接出现卡顿如何解决
  • 原文地址:https://www.cnblogs.com/butterflydew/p/9791887.html
Copyright © 2011-2022 走看看