思路
一 · 建输水厂
在越高的地方水能输的地方越多(这个是众所周知的)。然后用一个大根堆把与湖泊毗邻的第 1 行的城市由高到低排序,由高到低建输水厂。
二 · 建输水管
输水方向有四种(向上,向左,向下,向右),而且城市高度要依次递减才可以输水。而向上可以不做计算原因如图:
![]()
图中 h1>h3>h4>h2 ,因为 h1>h2 ,所以可以从 1 输水到 2 ,如图:
![]()
现在只需要向三个方向(向左,向下,向右)去枚举,然后比较高度看能不能往这个方向输水。
三 · 判断结果
1 . 可以输水的每一个干旱区的城市
在枚举每个输水厂输水范围是,标记哪些城市有水。只要第 n 行的每一个城市都有水,那么就可以直接输出答案。
2 . 不可以输水的每一个干旱区的城市
在枚举完每一个与湖泊毗邻的城市时,第 n 行还有城市没有水,那么枚举第 n 行所有城市,把没有水的城市总数记录下来,输出答案。
代码
#include<bits/stdc++.h>
const int N=1010;
using namespace std;
int n,m,dx[5]={-1,0,1,0},dy[5]={0,1,0,-1},vis[N][N],h[N][N],l[N][N],r[N][N];
void dfs(int x,int y){
vis[x][y]=1;
for(int i=0;i<4;i++){
int x1=x+dx[i],y1=y+dy[i];
if(x1<1||x1>n||y1<1||y1>m||h[x][y]<=h[x1][y1]) continue;
if(!vis[x1][y1]) dfs(x1,y1);
l[x][y]=min(l[x][y],l[x1][y1]);
r[x][y]=max(r[x][y],r[x1][y1]);
}
}
int main(){
scanf("%d%d",&n,&m);
memset(l,21000000,sizeof l);
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
scanf("%d",&h[i][j]);
if(i==n) l[i][j]=r[i][j]=j;
}
}
for(int i=1;i<=m;i++) if(!vis[1][i]) dfs(1,i);
bool check=true;
int ans=0;
for(int i=1;i<=m;i++){
if(!vis[n][i]){
check=false;
ans++;
}
}
if(!check){
cout<<0<<endl<<ans<<endl;
return 0;
}
int left=1,right=r[1][1];
while(left<=m){
for(int i=1;i<=m;i++) if(l[1][i]<=left) right=max(right,r[1][i]);
left=right+1;
ans++;
}
cout<<1<<endl<<ans<<endl;
return 0;
}