【问题描述】
有一个n行m列的网格,每个格子是边长为10米的正方形,网格四周是无限高的墙壁,第i行第j列每个格子的海拔高度为h[i][j]。现在网格中有T立方米的水,请你计算网格中的水平面的海拔高度,以及有水格子数目。注意,在网格中,所有有水格子的水平面的海拔高度相同,所以有水格子的数量为海拔高度严格小于水平面高度的格子数目。
【输入格式】
第一行整数n和m,表示网格有n行m列。
接下来是n行m列的矩阵,第i行第j列的数字为对应格子的海拔高度h[i][j]。
最后一行为整数T,表示网格中水的体积。
【输出格式】
第一行为一个实数,表示水平面的海拔高度,保留2位小数。
第二行为一个整数,表示有水格子的数目。
【输入样例】
3 3
25 37 45
51 12 34
94 83 27
10000
【输出样例】
46.67
6
【数据范围】
1<=n,m<=30
0<=h[i][j]<=1,000,000
1<=T<=1,000,000,000
注:该题取自学校OJ,与原题的多组数据输入有区别。
思路:本来想用贪心算法做,但是感觉有些复杂,然后看到数据是double类型的,而且二分猜答案的结果可以很简单check,因此用二分猜答案完成。
先猜一个值,然后验证这个值计算出来的水的体积与T比较,若小于则可以往右边猜,若大于则往左边猜。
/*
Name: flood.cpp
Copyright: Twitter & Instagram @stevebieberjr
Author: @stevebieberjr
Date: 25-07-16 10:02
*/
#include<cstdio>
#include<algorithm>
using namespace std;
int n,m;
double T,h[35*35];
//二分猜答案
int check(double p)
{
double sum=0;
int i;
for(i=1;i<=n*m;i++) //遍历每个点
{
if(h[i]<p) sum+=(p-h[i])*100; //高度小于猜的水平面高度,计算水的体积
if(sum>T) //若水的体积已经超过T,break
{
break;
}
}
if(i<n*m || sum>T) return 0; //sum>T的判断考试没有写错了一组数据,多一些判断总是好的
return 1;
}
int main()
{
freopen("flood.in","r",stdin);
freopen("flood.out","w",stdout);
scanf("%d%d",&n,&m);
for(int i=1;i<=n*m;i++)
{
scanf("%lf",&h[i]);
}
scanf("%lf",&T);
sort(h+1,h+1+(n*m)); //海拔从小到大排序
double mid=0,A=0,B=2000000000;
while(A<=B) //猜答案
{
mid=(A+B)/2.0;
if(check(mid)) A=mid+0.00000001;
else B=mid-0.00000001;
}
printf("%.2lf\n",A);
int ans=0; //计算有水格子的数目,也可在猜答案时计算
for(int i=1;i<=n*m;i++)
{
if(h[i]<A) ans++;
}
printf("%d\n",ans);
return 0;
}