• [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
    %d
    ",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
    %d
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    2030
    2019
    2018
    在 《检验反相能力, 一题不会者 不配反相》 里 的 回复
    我转载了 历史吧 的 一个 帖 《为什么很多人说中国古代没有科学?这不扯淡嘛》 到 反相吧
    在 简单的数学题也不会做了。做一算术题,看看是否老年痴呆! 里 的 回复
    谈谈 光速
    相对论 的 时空观 本身 就会 导致 一个 绝对 的 参照系
    对 薛定谔 波函数, 我 关心 它的 推导依据, 不太关心 数学形式
    霍奇猜想 (二)
  • 原文地址:https://www.cnblogs.com/Mrsrz/p/7511653.html
Copyright © 2020-2023  润新知