【题目描述】
在一个遥远的国度,一侧是风景秀美的湖泊,另一侧则是漫无边际的沙漠。该国的行政区划十分特殊,刚好构成一个N行M列的矩形,如上图所示,其中每个格子都代表一座城市,每座城市都有一个海拔高度。为了使居民们都尽可能饮用到清澈的湖水,现在要在某些城市建造水利设施。水利设施 有两种,分别为蓄水厂和输水站。蓄水厂的功能是利用水泵将湖泊中的水抽取到所在城市的蓄水池中。因此,只有与湖泊毗邻的第1行的城市可以建造蓄水厂。而输水站的功能则是通 过输水管线利用高度落差,将湖水从高处向低处输送。故一座城市能建造输水站的前提,是存在比它海拔更高且拥有公共边的相邻城市,已经建有水利设施。由于第N行的城市靠近沙漠,是该国的干旱区,所以要求其中的每座城市都建有水利设施。那么,这个要求能否满足呢?如果能,请计算最少建造几个蓄水厂;如果不能,求干旱区中不可能建有水利设施的城市数目。
【输入描述】
输入的每行中两个数之间用一个空格隔开。输入的第一行是两个正整数N和M,表示矩形的规模。接下来N行,每行M个正整数,依次代表每座城市的海拔高度。
【输出描述】
输出有两行。如果能满足要求,输出的第一行是整数1,第二行是一个整数,代表最少建造几个蓄水厂;如果不能满足要求,输出的第一行是整数0,第二行是一个整数,代表有几座干旱区中的城市不可能建有水利设施。
【样例输入】
2 5
9 1 5 4 3
8 7 6 1 2
【样例输出】
1
1
【数据范围及提示】
某一样例说明:
源代码: #include<cstdio> #include<cstring> #include<algorithm> #define INF 1000000000 using namespace std; struct Node1 { int X,Y; }Q[250001]; struct Node2 { int Left,Right; }F[501]; int m,n,ans(0),Now,i[501][501],Num[501],x[4]={-1,1,0,0},y[4]={0,0,-1,1}; bool f[501][501]={0}; void BFS() { int Head(0),Tail(0); for (int a=1;a<=m;a++) { f[1][a]=true; Q[++Tail].X=1; Q[Tail].Y=a; } while (Head<Tail) { Node1 t=Q[++Head]; //新奇的结构体用法。 for (int a=0;a<4;a++) { Node1 T; T.X=t.X+x[a]; T.Y=t.Y+y[a]; if (T.X<1||T.X>n||T.Y<1||T.Y>m||i[T.X][T.Y]>=i[t.X][t.Y]||f[T.X][T.Y]) continue; f[T.X][T.Y]=true; Q[++Tail]=T; } } } void DFS(int X,int Y) //DFS找最小左边界和最大右边界。 { f[X][Y]=true; if (X==n) { F[Now].Left=min(F[Now].Left,Y); F[Now].Right=max(F[Now].Right,Y); } for (int a=0;a<4;a++) { int t1=X+x[a]; int t2=Y+y[a]; if (t1<1||t1>n||t2<1||t2>m||i[t1][t2]>=i[X][Y]||f[t1][t2]) continue; DFS(t1,t2); } } int main() { scanf("%d%d",&n,&m); for (int a=1;a<=n;a++) for (int b=1;b<=m;b++) scanf("%d",&i[a][b]); BFS(); for (int a=1;a<=m;a++) if (!f[n][a]) ans++; if (ans) { printf("0 %d",ans); return 0; } for (int a=1;a<=m;a++) { memset(f,false,sizeof(f)); //全新的开始。 Now=a; //全局变量的应用。 F[a].Left=m+1; F[a].Right=0; DFS(1,a); } Num[0]=0; for (int a=1;a<=m;a++) //线段覆盖DP。 { Num[a]=INF; for (int b=1;b<=m;b++) if (a>=F[b].Left&&a<=F[b].Right) Num[a]=min(Num[a],Num[F[b].Left-1]+1); } printf("1 %d",Num[m]); return 0; } /* 很全面的一道搜索题,挺有意思的。 思路: 先设所有河边城市都修建水站,BFS查看能不能覆盖沙漠城市; 再DFS每个河边城市,并记录它们最小左边界和最大右边界; 最后线段覆盖DP一下,求出最少应建造多少水站。 线段覆盖型动态规划: 设Num[i]表示覆盖1~i所需最少的线段数,则有状态转移方程(遍历所有线段): Num[i]=min(Num[i],Num[F[k].Left-1]+1),(F[k].Left <= i <= F[k].Right)。 反思教训: 思维应发散,经常考虑能不能用其他方法来解决这个难点。 */