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

题目

传送门

思路

经过思考可以发现一个水流到最后一行的覆盖必是一个连续的线段。对于最后一行没有标记的格子直接统计并输出即可。如果有解那么我们每次寻找每个点的左边界和右边界,也就是他们最多可以到达的地方。

代码

#include<bits/stdc++.h>
using namespace std;
int n,m;
int l[505][505];
int r[505][505];
int a[505][505]; 
bool vis[505][505];
int fx[6]={0,1,0,-1};
int fy[6]={1,0,-1,0};
void dfs(int x,int y){
	vis[x][y]=1;
	for(int i=0;i<4;i++){
		int tx=x+fx[i];
		int ty=y+fy[i];
		if(tx<1||ty<1||tx>n||ty>m||a[x][y]<=a[tx][ty])continue;
		if(!vis[tx][ty])dfs(tx,ty);
		l[x][y]=min(l[x][y],l[tx][ty]);
		r[x][y]=max(r[x][y],r[tx][ty]);
	}
}
int main(){
	std::ios::sync_with_stdio(false);
	std::cin.tie(0);
	std::cout.tie(0);
	memset(l,0x3f,sizeof(l));
	cin>>n>>m;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			cin>>a[i][j];
			if(i==n){
				l[i][j]=j;
				r[i][j]=j;
			}
		}
	}
	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++;
		}
	}
	if(ans){
		cout<<0<<'\n'<<ans;
		return 0;
	}
	int left=1,right=r[1][1];
	while(left<=m){
		for(int i=1;i<=m;i++){
			if(left>=l[1][i]){
				right=max(right,r[1][i]);
			}
		}
		left=right+1;
		ans++;
	}
	cout<<1<<'\n'<<ans;
	return 0;
} 
posted @ 2026-09-16 23:04  陈晨2011  阅读(11)  评论(0)    收藏  举报