在一个遥远的国度,一侧是风景秀美的湖泊,另一侧则是漫无边际的沙漠。该国的行政区划十分特殊,刚好构成一个N 行×M 列的矩形,如上图所示,其中每个格子都代表一座城市,每座城市都有一个海拔高度。
为了使居民们都尽可能饮用到清澈的湖水,现在要在某些城市建造水利设施。水利设施有两种,分别为蓄水厂和输水站。蓄水厂的功能是利用水泵将湖泊中的水抽取到所在城市的蓄水池中。
因此,只有与湖泊毗邻的第111 行的城市可以建造蓄水厂。而输水站的功能则是通过输水管线利用高度落差,将湖水从高处向低处输送。故一座城市能建造输水站的前提,是存在比它海拔更高且拥有公共边的相邻城市,已经建有水利设施。由于第NNN 行的城市靠近沙漠,是该国的干旱区,所以要求其中的每座城市都建有水利设施。那么,这个要求能否满足呢?如果能,请计算最少建造几个蓄水厂;如果不能,求干旱区中不可能建有水利设施的城市数目。
没有思路,瞎JB想后觉得可以从最底层往上一层层判断哪些点必需要建输水站,然后发现题目看错了要求的是蓄水池,输水站没有要求。然后从贪心的角度想到不能建蓄水池的点全部建输水站。(然后就没有然后了)。
用dfs从第一排搜索,如果水能流到沙漠区,在有解的情况下每个点可以流到的区一定是连续的区间,无解的情况下流到的区域就不一定是连续的但无解可以o(m)判断一下是否无解(即最下一排每个点是否都有被访问过)。那么用一个数组维护一下每个点能流到的区间,有解时贪心求一下选择最小区间段覆盖整个区间就完事了。如果第一排每个点都搜会有许多点重复搜索,因此可以用记忆化搜索。
#include<bits/stdc++.h>
using namespace std;
const int maxn = 600;
int n,m;
int mp[maxn][maxn];
int l[maxn][maxn],r[maxn][maxn];
int mx[4]={1,0,-1,0},my[4]={0,1,0,-1};
int vis[maxn][maxn];
struct ss{
int l,r;
}res[maxn];
bool cmp(ss a,ss b){
return a.l<b.l;
}
void dfs(int x,int y){
int xx,yy;
vis[x][y]=1;
for(int i = 0;i<4;i++){
xx=x+mx[i],yy=y+my[i];
if(xx<1||xx>n||yy<1||yy>m) continue;
if(mp[x][y]<=mp[xx][yy]) continue;
if(!vis[xx][yy]) dfs(xx,yy);
l[x][y]=min(l[x][y],l[xx][yy]);
r[x][y]=max(r[x][y],r[xx][yy]);
}
}
int main(){
scanf("%d%d",&n,&m);
for(int i = 1; i <= n; i++)
for(int j = 1; j <= m; j++)
scanf("%d",&mp[i][j]);
for(int i = 1; i <= n; i++)
for(int j = 1; j <= m; j++){
l[i][j]=0x3f3f3f3f;
r[i][j]=0;
}
for(int i = 1; i <= m; i++)
l[n][i]=r[n][i]=i;
for(int i = 1; i <= m; i++){
if(!vis[1][i]) dfs(1,i);
}
int ans = 0 ;
for(int i = 1; i <= m; i++){
if(!vis[n][i]) ans++;
}
for(int i = 1; i <= m; i++){
res[i]={l[1][i],r[1][i]};
}
if(ans>0){
printf("0\n%d",ans);
return 0;
}
else{
sort(res+1,res+m+1,cmp);
int curr=0,mxr=0;
int cnt = 0;
for(int i = 1; i <= m; i++){
if(res[i].l<=curr+1){
mxr=max(mxr,res[i].r);
}
else if(mxr>curr){
curr=mxr;
cnt++;
i--;
}
}
if(res[m].l<=curr+1&&res[m].r>curr){
curr=res[m].r;
cnt++;
}
printf("1\n%d\n",cnt);
}
}