洛谷p1514_引水入城(记忆化搜索+贪心)

在一个遥远的国度,一侧是风景秀美的湖泊,另一侧则是漫无边际的沙漠。该国的行政区划十分特殊,刚好构成一个N 行×M 列的矩形,如上图所示,其中每个格子都代表一座城市,每座城市都有一个海拔高度。
《洛谷p1514_引水入城(记忆化搜索+贪心)》

为了使居民们都尽可能饮用到清澈的湖水,现在要在某些城市建造水利设施。水利设施有两种,分别为蓄水厂和输水站。蓄水厂的功能是利用水泵将湖泊中的水抽取到所在城市的蓄水池中。
因此,只有与湖泊毗邻的第111 行的城市可以建造蓄水厂。而输水站的功能则是通过输水管线利用高度落差,将湖水从高处向低处输送。故一座城市能建造输水站的前提,是存在比它海拔更高且拥有公共边的相邻城市,已经建有水利设施。由于第NNN 行的城市靠近沙漠,是该国的干旱区,所以要求其中的每座城市都建有水利设施。那么,这个要求能否满足呢?如果能,请计算最少建造几个蓄水厂;如果不能,求干旱区中不可能建有水利设施的城市数目。

《洛谷p1514_引水入城(记忆化搜索+贪心)》
没有思路,瞎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);
 	}
}
点赞