【题目描述】
Jonh正在研制一种有趣的“水杯”:
1)底面是W x H 的相同小方格组成
2)每个小方格上放置一个底面是1x1的,高度是B的水晶块。
这些水晶块都粘贴在一块,之间不会漏水。
John在制成之前,想知道他所要制的这种“水杯”能最多装多少水?
【数据范围】
3 <= W <= 300, 3 <= H <= 300
1 <= B <= 1,000,000,000
【输入文件】
(juice.in)
第一行:两个整数: W 和 H
下面有H行:每行有W个整数。1+i行表示第i行的每个格子上的水晶块的高度。
【输出文件】
(juice.out)
只一个整数,表示最多可装水多少。1单位为:1(宽)*1(长)*1(高)
【样例输入】
4 5
5 8 7 7
5 2 1 5
7 1 7 1
8 9 6 9
9 8 9 9
【样例输出】
12
【样例解释】
两个高度为1的和一个高度为2的
可装水到高度为5;一个高度
为6的可装水到高度为7。共装
水2*4 + 3 + 1 = 12.
一开始想的是枚举每一层 验证有多少空白的上下左右有方块
后来看B的范围太大 只能放弃
也有机房小伙伴bfs写 写了一会也放弃了。。。
正解是堆
盛水的多少,不在于木桶上那块最长的木板,而在于木桶上最短的那块木板。
因此,我们从“边上”考虑,每次优先处理的是“最短的那块木板”,由于本题中间可能有更高的“块”,可以由外向内地逐步处理,“边”也逐步“加高”
5 8 7 7
5 2 1 5
7 1 7 1
8 9 6 9
9 8 9 9
我们首先处理的是(3,4) 发现它没法向内扩展 也没法向上下扩展
然后处理5 以处理(2,4)为例 它比(2,3)高 可以以(2,4)的高度围出一个至少为5的边框(因为高度小的排在前面)
那么可以将(2,3)更新为高度5 然后将(2,3)加入队列 作为新的边框 向内更新
蒟蒻不会堆怎么办 现成的优先队列啊!!!
另外还要注意输入的先列后行
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
const int mx[5]={0,1,0,-1,0};
const int my[5]={0,0,1,0,-1};
struct node{
int x,y,h;
bool operator<(node a1)const
{
if(h==a1.h)
{
if(x==a1.x)return y>a1.y;
return x>a1.x;
}
return h>a1.h;
}
};
priority_queue<node>q;
int m,n;
int s[313][313];
int z,a,b,c;
bool p[313][313];
void add(int x,int y,int h)
{
int xx,yy;
for(int k=1;k<=4;k++)
{
xx=x+mx[k],yy=y+my[k];
if(xx<1||xx>m||yy<1||yy>n)continue;
if(!p[xx][yy])
{
q.push((node){xx,yy,s[xx][yy]});
p[xx][yy]=1;
if(s[x][y]>s[xx][yy])
{
int t=s[x][y]-s[xx][yy];
s[xx][yy]=s[x][y];
z+=t;
}
}
}
}
int main()
{
freopen("juice.in","r",stdin);freopen("juice.out","w",stdout);
scanf("%d%d",&n,&m);
for(a=1;a<=m;a++)
for(b=1;b<=n;b++)
{
scanf("%d",&s[a][b]);
if(a==1||b==1||a==m||b==n)
{
q.push((node){a,b,s[a][b]});
p[a][b]=1;
}
}
while(!q.empty())
{
node u=q.top();
q.pop();
add(u.x,u.y,u.h);
}
cout<<z<<'\n';
return 0;
}