引水入城
Posted 【對策局】
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了引水入城相关的知识,希望对你有一定的参考价值。
【题目描述】
在一个遥远的国度,一侧是风景秀美的湖泊,另一侧则是漫无边际的沙漠。该国的行政区划十分特殊,刚好构成一个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 100000000 using namespace std; struct Node { int x,y; }h[300001]; struct node { int left,right; }F[501]; int m,n,now,ans(0),num[501],i[501][501]; const int sum[4][2]={{0,1},{1,0},{0,-1},{-1,0}}; bool f[501][501]={0}; void BFS() //本蒟蒻终于会BFS了。 { int head(0),tail(0); for (int a=1;a<=m;a++) { f[1][a]=true; h[++tail].x=1; h[tail].y=a; } while (head<tail) { Node t=h[++head]; //新奇的结构体用法。 for (int a=0;a<4;a++) //此数组的懒惰用法应值得借鉴。 { Node s; s.x=t.x+sum[a][0]; s.y=t.y+sum[a][1]; if (s.x<1||s.x>n||s.y<1||s.y>m) continue; if (i[s.x][s.y]>=i[t.x][t.y]) continue; if (f[s.x][s.y]) continue; f[s.x][s.y]=true; h[++tail]=s; } } } 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++) { Node t; t.x=x+sum[a][0]; t.y=y+sum[a][1]; if (t.x<1||t.x>n||t.y<1||t.y>m) continue; if (i[t.x][t.y]>=i[x][y]) continue; if (!f[t.x][t.y]) DFS(t.x,t.y); } } 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\n%d",ans); return 0; //还能这么玩。 } printf("1\n"); for (int a=1;a<=m;a++) { memset(f,0,sizeof(f)); //全新的开始。 now=a; //全局变量的应用。 F[now].left=m+1; F[now].right=0; DFS(1,a); } num[0]=0; //num[i]表示1~i所需的线段数最小值。 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("%d",num[m]); return 0; }
以上是关于引水入城的主要内容,如果未能解决你的问题,请参考以下文章