题目:
分析:
一个水坑如果是想流出去,就要积水积累到四周可以流出的最小高度,就是它最后积的水。
将问题转换成:每个格子都可以向四方走,求从每个格子出发,走到边缘所经过的路径上点权最大值的最小值。
也就是说,一个点都可以向四方走,但要求花费最小,并能够到达边缘的点。
对于一些花费大的边,明显可以被删除也不会影响答案->考虑最小生成树(最小生成树保证点之间两两连通,花费大的边会被删去)
对于一个点,它对它的四方连边,边权为两个点之间的较大值,如果可以通向边缘,就对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 */