10.3
water
思路:
一个块的高度就是从这走出矩形所有路径上最大值的最小。相邻块连边,边权为两块的较大值,矩形边界的块(人工加一圈为0的圈)向“矩形外”连(把“矩形外”抽象成一个S点),权值为 max(高度, 0) ,做最小生成树。
这样就能找到最优解,那么怎么统计答案呢?从S开始dfs记录到每个点的路径最大值。
时间复杂度 O(nmlognm)
贴一份 berrykanry的代码
#include<stdio.h>
#include<algorithm>
using namespace std;
typedef long long dnt;
struct edge{
int u,v,last;
dnt w;
}ad[2000010],ed[2000010];
int n,m,fa[200010],head[2000010];
dnt dep[2000010],a[2000010];
int num=0,tot=0;
bool cmp(const edge &a,const edge &b){
return a.w<b.w;
}
void ade(int u,int v,dnt w){
tot++;
ad[tot].u=u,ad[tot].v=v,ad[tot].w=w;
}
void add(int u, int v, dnt w){
num++;
ed[num].v=v;
ed[num].w=w;
ed[num].last=head[u];
head[u]=num;
}
int getfather(int x){
if(x==fa[x]) return x;
return fa[x]=getfather(fa[x]);
}
void Kruscal(){
int cnt = 0;
for(int i=0; i<=n*m; i++) fa[i]=i;
sort(ad+1, ad+tot+1, cmp);
for(int i=1; i<=tot; i++){
int x = getfather(ad[i].u), y = getfather(ad[i].v);
if(x != y){
fa[x] = y, cnt++;
add(ad[i].u, ad[i].v, ad[i].w);
add(ad[i].v, ad[i].u, ad[i].w);
}
if(cnt == n*m) break ;
}
}
void dfs(int u, int f){
for(int i=head[u]; i; i=ed[i].last){
int v = ed[i].v;
if(v == f) continue ;
dep[v] = max(dep[u], ed[i].w);
dfs(v, u);
}
}
int main(){
freopen("water.in", "r", stdin);
freopen("water.out", "w", stdout);
scanf("%d%d", &n, &m);
for(int i=1; i<=n; i++)
for(int j=1; j<=m; j++)
scanf("%I64d", &a[(i-1)*n+j]);
for(int i=1; i<=n; i++)
for(int j=1; j<=m; j++){
int S=(i-1)*n+j;
int A=(j==1) ? 0 : (i-1)*n+j-1;
int B=(j==m) ? 0 : (i-1)*n+j+1;
int C=(i==1) ? 0 : (i-2)*n+j;
int D=(i==n) ? 0 : i*n+j;
ade(S,A,max(a[S],a[A])),ade(S,B,max(a[S],a[B]));
ade(S,C,max(a[S],a[C])),ade(S,D,max(a[S],a[D]));
}
Kruscal();
dfs(0, 0);
for(int i=1; i<=n; i++, printf("\n"))
for(int j=1;j<=m;j++){
int S=(i-1)*n+j;
printf("%I64d ",max(dep[S]-a[S],1LL*0));
}
return 0;
}
’搜索‘做法
从外向内dfs,a为实际高度,h为积水后高度。
用堆维护起点(由大到小更新)
#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
#define LL long long
#define N 400
using namespace std;
struct place{
int x, y;
LL v;
bool operator < (const place &a) const{
return v > a.v;
}
};
inline int read(){
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
priority_queue <place> q;
int n,m;
LL a[N][N], h[N][N];
bool vis[N][N];
int dx[4] = {1,-1,0,0};
int dy[4] = {0,0,1,-1};
int main(){
freopen ("water.in", "r", stdin);
freopen ("water.out", "w", stdout);
n = read(), m = read();
for(register int i=1; i<=n; ++i)
for(register int j=1; j<=m; ++j)
a[i][j] = read(), h[i][j] = a[i][j];
for(register int i=0; i<=n+1; ++i)
for(register int j=0; j<=m+1; ++j)
if(i==0 || i==n+1 || j==0 || j==m+1){
vis[i][j] = 1;
q.push((place){i, j, h[i][j]});
}
while( !q.empty() ){
place u = q.top(); q.pop();
for(int i=0; i<=3; ++i){
int x = u.x + dx[i], y = u.y + dy[i];
if(x>=0 && x<=n+1 && y>=0 && y<=m+1 && !vis[x][y]){
if(h[x][y] < h[u.x][u.y]) h[x][y] = h[u.x][u.y];
vis[x][y] = 1;
q.push((place){x, y, h[x][y]});
}
}
}
for(register int i=1; i<=n; ++i){
for(register int j=1; j<=m; ++j)
printf("%d ", h[i][j] - a[i][j]);
cout << endl;
}
return 0;
}