暑假考试题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("\n");
    }/**/
    return 0;
}
/*
3 3
4 4 0
2 1 3
3 3 -1
*/

猜你喜欢

转载自www.cnblogs.com/mowanying/p/11436717.html