描述
在一个遥远的国度,一侧是风景秀美的湖泊,另一侧则是漫无边际的沙漠。该国的行政区划十分特殊,刚好构成一个N行M列的矩形,其中每个格子都代表一座城市,每座城市都有一个海拔高度。
为了使居民们都尽可能饮用到清澈的湖水,现在要在某些城市建造水利设施。水利设施有两种,分别为蓄水厂和输水站。蓄水厂的功能是利用水泵将湖泊中的水抽取到所在城市的蓄水池中。因此,只有与湖泊毗邻的第1行的城市可以建造蓄水厂。而输水站的功能则是通过输水管线利用高度落差,将湖水从高处向低处输送。故一座城市能建造输水站的前提,是存在比它海拔更高且拥有公共边的相邻城市,已经建有水利设施。
由于第N行的城市靠近沙漠,是该国的干旱区,所以要求其中的每座城市都建有水利设施。那么,这个要求能否满足呢?如果能,请计算最少建造几个蓄水厂;如果不能,求干旱区中不可能建有水利设施的城市数目。
格式
输入格式
输入文件的每行中两个数之间用一个空格隔开。
输入的第一行是两个正整数N和M,表示矩形的规模。
接下来N行,每行M个正整数,依次代表每座城市的海拔高度。
输出格式
输出有两行。如果能满足要求,输出的第一行是整数1,第二行是一个整数,代表最少建造几个蓄水厂;如果不能满足要求,输出的第一行是整数0,第二行是一个整数,代表有几座干旱区中的城市不可能建有水利设施。
限制
每个测试点1s
提示
本题共有10个测试数据,每个数据的范围如下表所示:
测试数据编号 能否满足要求 N M
1 不能 ≤ 10 ≤ 10
2 不能 ≤ 100 ≤ 100
3 不能 ≤ 500 ≤ 500
4 能 = 1 ≤ 10
5 能 ≤ 10 ≤ 10
6 能 ≤ 100 ≤ 20
7 能 ≤ 100 ≤ 50
8 能 ≤ 100 ≤ 100
9 能 ≤ 200 ≤ 200
10 能 ≤ 500 ≤ 500
对于所有的10个数据,每座城市的海拔高度都不超过10^6。
来源
noip2010提高组复赛
解析:1.从上往下进行染色,然后统计第 n 行未被染色的数量 s ,若s>0,则输出 0 s;
为什么选择从上往下染色,而不是下方的从下往上染色,还能生一次搜索呢。(我买个关子,自己做的时候就知道了。)
2.从下往上进行两次染色,第一次,从左往右进行染色,得到每一个第一行的点所能覆盖的左界;
第二次,从右往左进行染色,得到每一个第一行的点所能覆盖的右界。
3.贪心。假设当前覆盖区间为[l,r],枚举第一行的点,从中选取能与当前区间[l,r]连接起来,并且向右延伸最远的点,作为下一个蓄水场建立点。
代码:
#include<cstdio> #include<algorithm> #define maxn 500 using namespace std; int n,m,h[maxn+20][maxn+20]; int color[maxn+20][maxn+20]; struct node{int x,y;}q[maxn*maxn+20]; struct tnode{int left,right;}p[maxn+20]; int dx[4]={0,-1,0,1},dy[4]={-1,0,1,0}; bool cmp(tnode a,tnode b) { if(a.left<b.left)return 1; if(a.left>b.left)return 0; return a.right>b.right; } void bfs_1(int a,int b) { int i,j,k,l=0,r=0; q[0].x=a,q[0].y=b; while(l<=r) { for(k=0;k<4;k++) { i=q[l].x+dx[k],j=q[l].y+dy[k]; if(i>=1 && i<=n && j>=1 && j<=m && color[i][j]!=-1 && h[i][j]<h[q[l].x][q[l].y]) q[++r].x=i,q[r].y=j,color[i][j]=-1; } l++; } } void bfs_2(int a,int b,int c) { int i,j,k,l=0,r=0; q[0].x=a,q[0].y=b; while(l<=r) { for(k=0;k<4;k++) { i=q[l].x+dx[k],j=q[l].y+dy[k]; if(i>=1 && i<=n && j>=1 && j<=m && color[i][j]<c && h[i][j]>h[q[l].x][q[l].y]) q[++r].x=i,q[r].y=j,color[i][j]=color[a][b]; } l++; } } int main() { int i,j,k,s,l,r; scanf("%d%d",&n,&m); for(i=1;i<=n;i++) for(j=1;j<=m;j++) scanf("%d",&h[i][j]); for(i=1;i<=m;i++)color[1][i]=-1; for(i=1;i<=m;i++)bfs_1(1,i); for(s=0,i=1;i<=m;i++)if(color[n][i]!=-1)s++; if(s>0) { printf("%d\n%d\n",0,s); return 0; } for(i=1;i<=m;i++)p[i].left=p[i].right=0; for(i=1;i<=m;i++) if(color[n][i]<1)color[n][i]=i,bfs_2(n,i,1); for(i=1;i<=m;i++) if(color[1][i]>=1 && color[1][i]<=m)p[i].left=color[1][i]; for(i=m;i>=1;i--) if(color[n][i]<m+1)color[n][i]=m+i,bfs_2(n,i,m+1); for(i=1;i<=m;i++) if(color[1][i]>=m+1 && color[1][i]<=m+m)p[i].right=color[1][i]-m; s=0,r=0; while(r<m) { for(k=0,i=1;i<=m;i++) if(p[i].left==r+1)k=max(k,p[i].right); r=k,s++; for(i=1;i<=m;i++) if(p[i].right>r && p[i].left<=r)p[i].left=r+1; } printf("%d\n%d\n",1,s); return 0; }