zoukankan      html  css  js  c++  java
  • 暑假考试题8:water(最小生成树)

    题目:

     分析:

    一个水坑如果是想流出去,就要积水积累到四周可以流出的最小高度,就是它最后积的水。

    将问题转换成:每个格子都可以向四方走,求从每个格子出发,走到边缘所经过的路径上点权最大值的最小值

    也就是说,一个点都可以向四方走,但要求花费最小,并能够到达边缘的点。

    对于一些花费大的边,明显可以被删除也不会影响答案->考虑最小生成树最小生成树保证点之间两两连通,花费大的边会被删去

    对于一个点,它对它的四方连边,边权为两个点之间的较大值,如果可以通向边缘,就对0点连边。(边缘用0这个点代替

    然后答案的统计就是从0点出发,边走边取max,将max累入走到那个点的答案。(原题上其实是从每一个点出发,最后到达0点的最大值,而这里反了过来)

    #include<bits/stdc++.h>
    using namespace std;
    #define nn 305
    #define N 90005
    #define M 400005
    #define inf 2100000000
    int cnt=0,tot=0,num=0,bian=0,fa[N],to[M],nex[M],w[M],head[N],x[N],y[N],id[nn][nn],a[nn][nn],ans[nn][nn];
    struct node{ int a,b,w; } e[M];
    bool cmp(const node &a,const node &b) { return a.w<b.w; }
    void add2(int a,int b,int ww) { to[++tot]=b; nex[tot]=head[a]; w[tot]=ww; head[a]=tot; }
    void add1(int a,int b,int ww){ e[++num].a=a,e[num].b=b,e[num].w=ww; }
    int read()
    {
        int x=0; int fl=1; char ch=getchar();
        while(ch>'9'||ch<'0') { if(ch=='-') fl=-1; ch=getchar(); }
        while(ch<='9'&&ch>='0') x=x*10+ch-'0',ch=getchar();
        return x*fl;
    }
    int find(int x)
    {
        if(fa[x]==x) return x;
        return fa[x]=find(fa[x]);
    }
    void kru()
    {
        for(int i=1;i<=cnt;i++) fa[i]=i;
        sort(e+1,e+1+num,cmp);
        for(int i=1;i<=num;i++){
            int f1=find(e[i].a),f2=find(e[i].b);
            if(f1==f2) continue;
            bian++;
            fa[f1]=f2; add2(e[i].a,e[i].b,e[i].w); add2(e[i].b,e[i].a,e[i].w);
            if(bian>=cnt) break;
        }
    }
    void dfs(int u,int f,int mx)
    {
        for(int i=head[u];i;i=nex[i]){
            int v=to[i];
            if(v==f) continue;
            int xx=x[v],yy=y[v];
            ans[xx][yy]=max(mx,w[i]);
            dfs(v,u,max(mx,w[i]));
        }
    }
    int main()
    {
        freopen("water.in","r",stdin);
        freopen("water.out","w",stdout);
        int n,m;
        n=read(); m=read();
        for(int i=1;i<=n;i++)
         for(int j=1;j<=m;j++)
          a[i][j]=read(),id[i][j]=++cnt,x[cnt]=i,y[cnt]=j;
        for(int i=1;i<=n;i++)
         for(int j=1;j<=m;j++){
             add1(id[i][j],id[i-1][j],max(a[i][j],a[i-1][j]));//0点的权值为0 直接连就好了 
             add1(id[i][j],id[i+1][j],max(a[i][j],a[i+1][j]));
             add1(id[i][j],id[i][j-1],max(a[i][j],a[i][j-1]));
             add1(id[i][j],id[i][j+1],max(a[i][j],a[i][j+1]));
        }
        kru();
        dfs(0,-1,-inf);
        for(int i=1;i<=n;i++){
         for(int j=1;j<=m;j++)
             printf("%d ",ans[i][j]-a[i][j]);//ans其实统计的是最后流出去的高度 所以还要-a[i][j] 
             printf("
    ");
        }/**/
        return 0;
    }
    /*
    3 3
    4 4 0
    2 1 3
    3 3 -1
    */
  • 相关阅读:
    linux命令行
    mybatis中#{}和${}的区别
    @InitBinder的作用
    mui 实用封装销毁页面
    【SQLite】简单的基本使用步骤
    常用的一些操作方法
    【HttpWeb】Post和GET请求基本封装
    【接口验证】特性验证参数
    小谈单例模式
    vs下开端口直接调试iis
  • 原文地址:https://www.cnblogs.com/mowanying/p/11436717.html
Copyright © 2011-2022 走看看