2019.8.16
T2 water
官方题解:
一个块的水平面高度就是从这个块走出矩形的所有路径上的最 大值的最小值。 相邻块连边,权值为两块的较大值,矩形 边界的块向“矩形外”连边,权值为 max(高度,0)。 做最小生成树。 时间复杂度 O(nmlognm)。
瓶颈生成树:满足最大的边最小。
最小生成树:也就是最小瓶颈树。
我来说说:
1.为什么能用最小生成树??
正如题解,一个格子的水是由它流向外围的所有路径中,每条路径上的最大值 的最小值。(木桶原理)
可以用bfs解决。
最小生成树可以求出最小的路径,再在该路径上取最大值即为最大蓄水量。
2.一开始想的是对每一个格子kruscal,但发现可以一次解决所有答案。
3.对每一个点,寻找该点所在联通块时,O(N)遍历会TLE(70),用vector解决。
好题,难想。
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxn=310; 4 const int N=maxn*maxn*4; 5 const int mod=1e9+7; 6 int dx[]={0,1,-1,0,0}; 7 int dy[]={0,0,0,1,-1}; 8 int n,m; 9 int zb(int i,int j){return (i-1)*m+j;} 10 int mp[maxn][maxn],cnt[maxn][maxn]; 11 struct Edge{ 12 int w,f,to,nxt; 13 bool operator < (const Edge &b) const { 14 return w<b.w; 15 } 16 }ed[N]; 17 int head[N],ecnt; 18 void addedge(int f,int to,int w){ 19 ed[++ecnt].w=w; 20 ed[ecnt].f=f; 21 ed[ecnt].to=to; 22 ed[ecnt].nxt=head[f]; 23 head[f]=ecnt; 24 } 25 int fa[N],ans[N]; 26 int find(int x){ 27 if(fa[x]==x) return x; 28 return fa[x]=find(fa[x]); 29 } 30 vector <int> v[N]; 31 void deal_(){ 32 for(int i=0;i<=n*m;i++) fa[i]=i,v[i].push_back(i); 33 int target=0; 34 for(int i=1;i<=ecnt;i++){ 35 int a=ed[i].f,b=ed[i].to; 36 int ffa=find(a),ffb=find(b); 37 if(ffa!=ffb){ 38 if(ffb==target&&ffa!=target) swap(ffa,ffb),swap(a,b); 39 if(ffa==target){ 40 for(int j=0;j<v[ffb].size();j++){ 41 ans[v[ffb][j]]=ed[i].w; 42 } 43 } 44 fa[ffb]=ffa; 45 for(int j=0;j<v[ffb].size();j++){ 46 v[ffa].push_back(v[ffb][j]); 47 } 48 } 49 } 50 } 51 int main(){ 52 scanf("%d%d",&n,&m); 53 for(int i=1;i<=n;i++) 54 for(int j=1;j<=m;j++) 55 scanf("%d",&mp[i][j]); 56 for(int i=1;i<=n;i++) 57 for(int j=1;j<=m;j++){ 58 for(int d=1;d<=4;d++){ 59 if(i+dx[d]<=0||i+dx[d]>n||j+dy[d]<=0||j+dy[d]>m){ 60 addedge(0,zb(i,j),max(mp[i][j],0)); 61 // addedge(zb(i,j),0,max(mp[i][j],0)); 62 continue; 63 } 64 addedge(zb(i,j),zb(i+dx[d],j+dy[d]),max(mp[i][j],mp[i+dx[d]][j+dy[d]])); 65 // addedge(zb(i+dx[d],j+dy[d]),zb(i,j),max(mp[i][j],mp[i+dx[d]][j+dy[d]])); 66 } 67 } 68 sort(ed+1,ed+1+ecnt); 69 memset(ans,-1,sizeof ans); 70 deal_(); 71 for(int i=1;i<=n;i++){ 72 for(int j=1;j<=m;j++){ 73 printf("%d ",ans[zb(i,j)]-mp[i][j]); 74 } 75 puts(""); 76 } 77 return 0; 78 79 }