思路
一 · 建输水厂
在越高的地方水能输的地方越多(这个是众所周知的)。然后用一个大根堆把与湖泊毗邻的第 $1$ 行的城市由高到低排序,由高到低建输水厂。
二 · 建输水管
输水方向有四种(向上,向左,向下,向右),而且城市高度要依次递减才可以输水。而向上可以不做计算原因如图:
图中 $h_1>h_3>h_4>h_2$ ,因为 $h_1>h_2$ ,所以可以从 $1$ 输水到 $2$ ,如图:
现在只需要向三个方向(向左,向下,向右)去枚举,然后比较高度看能不能往这个方向输水。
三 · 判断结果
1 . 可以输水的每一个干旱区的城市
在枚举每个输水厂输水范围是,标记哪些城市有水。只要第 $n$ 行的每一个城市都有水,那么就可以直接输出答案。
2 . 不可以输水的每一个干旱区的城市
在枚举完每一个与湖泊毗邻的城市时,第 $n$ 行还有城市没有水,那么枚举第 $n$ 行所有城市,把没有水的城市总数记录下来,输出答案。
代码(cpp)
#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;
}