water(最小生成树)

这道题有两个方法。

1.最小生成树。(我改的此法,此法是正解)

其实每个块所在位置的积水高度就是从这个块到矩形外的所有路径中最大值的最小值。

对于一个块我们把它向四周的块连边,每条边的权值为两端点点权的最大值。(因为所有路径中最大值才有用)

如果这个块在矩形的边缘,那么它向矩形外(虚节点)连边,边权为max(这块的高度,0)

我们建一棵最小生成树(即是最大值的最小值),从虚节点开始遍历这个图,记录虚节点到每个块路径上的最大值。

即是每个块所在位置的积水高度。

如果这个块的高度大于块所在位置的积水高度。那么积水深度为0.

如果这个块的高度小于块所在位置的积水高度。那么积水深度为0积水高度-这个块的高度。

2.dfs+剪枝。

把每个块按高度从大到小排序。for每一个块每个块所在位置的积水高度是由周围比它高的点所在位置的积水高度的最小值。

剪枝,先错误的dfs,贪心的dfs,每个点一直往比它小的点搜,如果可以搜到矩形外,这个块所在位置的积水深度就为0;

然后for的时候,以求出的块则不用dfs了,第二遍dfs时,遇到积水深度就为0的块就return,,,,

#include<bits/stdc++.h>
using namespace std;
int n,m;
int tp,top,fa[90010],a[305][305],b[305][305];
int zl[4][2] = {{0,1},{1,0},{-1,0},{0,-1}};
int tpp, nexx[1000010],hh[1000010],toww[1000010],tovv[1000010]; 
int  vis[90010], gao[90010], cnt;
struct node
{
	int tov,tow,tox;
};
node q[2000010];
bool cmp(const node a,const node b)
{
	return a.tow < b.tow;
}
void read(int &x)
{
	x = 0;int f = 0;
	char c = getchar();
	while(c < '0' || c > '9')
	{
		if(c == '-') f = 1;
		c = getchar();
	}
	while(c >= '0' && c <= '9')
	{
		x = x * 10 + c - '0';
		c = getchar();
	}
	if(f) x = -x;
}
void add(int x,int y,int w)
{
	tp++;
	q[tp].tox = x;
	q[tp].tov =y;
	q[tp].tow = w;
}
void add1(int x,int y,int w)
{
	tpp++;
	nexx[tpp] = hh[x];
	hh[x] = tpp;
	toww[tpp] = w;
	tovv[tpp] = y;
}
int find(int x)
{
	if(fa[x] == x) return x;
	return fa[x] = find(fa[x]);
}
void dfs(int x,int f)
{
  for(int i = hh[x]; i; i = nexx[i])
  {
  	int v = tovv[i];
  	if(v == f) continue;
  	  gao[v] = max(gao[x],toww[i]);
     dfs(v,x);
  }
}
int main()
{
	read(n); read(m);
	for(int i = 1; i <= n; i++)
	 for(int j = 1; j <= m; j++)
	 {
	 	read(a[i][j]);
	 	b[i][j] = ++cnt;
	 	fa[cnt] = cnt;
	 }
	for(int i = 1; i <= m; i++)
	{ 
	    add(cnt+1,b[1][i],max(a[1][i],0));
		add(cnt+1,b[n][i],max(a[n][i],0));
	}
	for(int i = 2; i <= n-1; i++)
	{
		add(cnt+1,b[i][1],max(a[i][1],0));
		add(cnt+1,b[i][m],max(a[i][m],0));
	}
	for(int i = 1; i <= n; i++)
	 for(int j = 1; j <= m; j++)
	 {
	 		for(int k = 0; k <= 3; k++)
	 		{
	 			int xx = i + zl[k][0];
	 		int yy = j + zl[k][1];
	 		if(xx >= 1 && xx <= m && yy >= 1 && yy <= n)
	 	    add(b[i][j],b[xx][yy],max(a[i][j],a[xx][yy]));	
	 		}
	}
	 sort(q+1,q+1+tp,cmp);
   for(int i = 1; i <= tp; i++)
   {
   	 int r1 = find(q[i].tov);
   	 int r2 = find(q[i].tox);
      if(r1 != r2)
      {
      	top++;
      	fa[r1] = r2;
       add1(q[i].tox,q[i].tov,q[i].tow);
       add1(q[i].tov,q[i].tox,q[i].tow);
	    if(top == cnt) break;
	  }
   } 
   dfs(cnt+1,cnt+1);
   for(int i = 1; i <= n; i ++)
    {
    	for(int j = 1; j < m; j++)
       { 
    	if(gao[b[i][j]] <= a[i][j]) printf("0 ");
        else printf("%d ",gao[b[i][j]] - a[i][j]);
	   }
       if(gao[b[i][m]] <= a[i][m]) printf("0");
       else printf("%d",gao[b[i][m]] - a[i][m]);
       cout << endl;
    }
   return 0;
} 

猜你喜欢

转载自blog.csdn.net/Bluelanzhan/article/details/83419163