题解:P1514 [NOIP 2010 提高组] 引水入城

思路

一 · 建输水厂

在越高的地方水能输的地方越多(这个是众所周知的)。然后用一个大根堆把与湖泊毗邻的第 行的城市由高到低排序,由高到低建输水厂。

二 · 建输水管

输水方向有四种(向上,向左,向下,向右),而且城市高度要依次递减才可以输水。而向上可以不做计算原因如图:

图中 ,因为 ,所以可以从 输水到 ,如图:

现在只需要向三个方向(向左,向下,向右)去枚举,然后比较高度看能不能往这个方向输水。

三 · 判断结果

1 . 可以输水的每一个干旱区的城市

在枚举每个输水厂输水范围是,标记哪些城市有水。只要第 行的每一个城市都有水,那么就可以直接输出答案。

2 . 不可以输水的每一个干旱区的城市

在枚举完每一个与湖泊毗邻的城市时,第 行还有城市没有水,那么枚举第 行所有城市,把没有水的城市总数记录下来,输出答案。

代码

#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;
}
posted @ 2025-03-15 17:02  liketaem  阅读(15)  评论(0)    收藏  举报  来源