[NOIP2010提高组]引水入城

Posted Mrsrz

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[NOIP2010提高组]引水入城相关的知识,希望对你有一定的参考价值。

题目:洛谷P1514、Vijos P1777、codevs1066。

题目大意:有一个$n×m$的矩阵,每个点都有一个高度,可以在第一行的任意点建立蓄水厂。现在要把水输到最后一行的所有点上,规定水只能流到高度比当前点小的点上。先让你判断能否输到所有点上,如能,输出最少建多少个蓄水厂;如不能,输出最多能输到几个点上。

解题思路:首先把第一行所有点塞进队列里,跑BFS,找出所有能到的点,然后判断能否输到最后一行所有点上。如果不能,输出最后一行能被输到的点的总数。如果能的话,我们依次把第一行每个点能输到的点求出来。

下面证明在能输到最后一行所有点的情况下,第一行每个点能输到最后一行的点一定构成一个连续的区间。

如果出现一个蓄水厂分流到两个不同的区间,那么有下图:

可以发现,红色区域由于已经被蓝色区域包围,所以无论如何都是无法流到的,说明如果有可行的方案,流到的一定是一个连续的区间。

然后就是区间覆盖问题,贪心一下就好了。

C++ Code:

#include<cstdio>
#include<queue>
#include<algorithm>
#include<cstring>
using namespace std;
int n,m,h[505][505],ans;
bool b[505][505];
queue<pair<int,int> >q;
const int dx[]={0,0,1,-1};
const int dy[]={-1,1,0,0};
struct QJ{
	int L,R;
	bool operator<(const QJ& rhs)const{
		if(L!=rhs.L)return L<rhs.L;
		return R>rhs.R;
	}
}a[505];
void bfs(){
	memset(b,1,sizeof b);
	for(int i=1;i<=m;++i){
		b[1][i]=false;
		q.push(make_pair(1,i));
	}
	while(!q.empty()){
		int x=q.front().first,y=q.front().second;
		q.pop();
		for(int i=0;i<4;++i){
			int lx=x+dx[i],ly=y+dy[i];
			if(ly>0&&ly<=m&&lx<=n&&b[lx][ly]&&h[x][y]>h[lx][ly]){
				b[lx][ly]=false;
				q.push(make_pair(lx,ly));
			}
		}
	}
}
void bfs2(int t){
	memset(b,1,sizeof b);
	b[1][t]=false;
	q.push(make_pair(1,t));
	int Lft=20000,Rgt=0;
	while(!q.empty()){
		int x=q.front().first,y=q.front().second;
		q.pop();
		if(x==n){
			if(y<Lft)Lft=y;
			if(y>Rgt)Rgt=y;
		}
		for(int i=0;i<4;++i){
			int lx=x+dx[i],ly=y+dy[i];
			if(ly>0&&ly<=m&&lx<=n&&b[lx][ly]&&h[x][y]>h[lx][ly]){
				b[lx][ly]=false;
				q.push(make_pair(lx,ly));
			}
		}
	}
	a[t].L=Lft;
	a[t].R=Rgt;
}
int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;++i)
	for(int j=1;j<=m;++j)scanf("%d",&h[i][j]);
	bfs();
	ans=0;
	for(int i=1;i<=m;++i)
	if(b[n][i])++ans;
	if(ans){
		printf("0\\n%d\\n",ans);
		return 0;
	}
	for(int i=1;i<=m;++i)
	bfs2(i);
	sort(a+1,a+m+1);
	int l=a[1].L,r=a[1].R;
	ans=1;
	while(r<m){
		int p,mx=0;
		for(int i=1;i<=m;++i){
			if(a[i].L<=l)continue;
			if(a[i].L>r+1)break;
			if(mx<a[i].R)mx=a[i].R,p=i;
		}
		l=a[p].L,r=a[p].R;++ans;
	}
	printf("1\\n%d\\n",ans);
	return 0;
}

 

以上是关于[NOIP2010提高组]引水入城的主要内容,如果未能解决你的问题,请参考以下文章

记忆化搜索+dp(洛谷1514 引水入城2010noip提高组)

NOIP2010 引水入城

CODEVS 1066/洛谷 P1514引水入城

luoguP1514 引水入城 题解(NOIP2010)

[NOIP2010] 引水入城

NOIP2010 引水入城